Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

892 lines
23 KiB

  1. /*
  2. * status line handler
  3. *
  4. */
  5. /*---includes-----------------------------------------------------------*/
  6. #include "windows.h"
  7. #include "string.h"
  8. #include "gutils.h"
  9. /* --- data structures ------------------------------------------------- */
  10. #define SF_MAXLABEL 80 /* no more than 80 in an item within the bar */
  11. /* Is this adequate for long pathnames on a
  12. hi-res screen?
  13. */
  14. typedef struct statel {
  15. int type; /* SF_BUTTON or SF_STATIC */
  16. int flags; /* SF_VAR => variable width
  17. SF_LEFT=> left aligned (else right)
  18. SF_RAISE=> paint as 'raised' 3d rect
  19. SF_LOWER=> paint as lowered 3D rect
  20. SF_SZMIN=>together with SF_VAR
  21. allows minimum size for
  22. var sized item
  23. SF_SZMAX=>see SZMIN and use nouse
  24. */
  25. int id; /* control id */
  26. int width; /* width of control in chars */
  27. char text[SF_MAXLABEL+1]; /* null-term string for label */
  28. RECT rc; /* used by status.c */
  29. } STATEL, * PSTATEL;
  30. typedef struct itemlist {
  31. int nitems;
  32. PSTATEL statels;
  33. int selitem; /* used by status.c */
  34. BOOL isselected; /* used by status.c */
  35. } ILIST, * PILIST;
  36. /* ------------------------------------------------------------------*/
  37. /* prototypes of routines in this module */
  38. void StatusCreateTools(void);
  39. void StatusDeleteTools(void);
  40. INT_PTR APIENTRY StatusWndProc(HWND, UINT, WPARAM, LPARAM);
  41. void StatusResize(HWND hWnd, PILIST pilist);
  42. int StatusCalcHeight(HWND hWnd, PSTATEL ip);
  43. int StatusCalcWidth(HWND hWnd, PSTATEL ip);
  44. PSTATEL StatusGetItem(PILIST plist, int id);
  45. void LowerRect(HDC hDC, LPRECT rcp);
  46. void RaiseRect(HDC hDC, LPRECT rcp);
  47. void StatusPaint(HWND hWnd, PILIST iplistp);
  48. void BottomRight(HDC hDC, LPRECT rcp, HPEN hpen, BOOL bCorners);
  49. void TopLeft(HDC hDC, LPRECT rcp, HPEN hpen, BOOL bCorners);
  50. void StatusButtonDown(HDC hDC, PSTATEL ip);
  51. void StatusButtonUp(HDC hDC, PSTATEL ip);
  52. void InitDC(HDC hdc);
  53. /*--global data---------------------------------------------------------*/
  54. HPEN hpenHilight, hpenLowlight;
  55. HPEN hpenBlack, hpenNeutral;
  56. HBRUSH hbrBackground; /* pieces and board */
  57. HFONT hFont;
  58. int status_charheight, status_charwidth;
  59. /* default pt size for font (tenths of a pt) */
  60. #define DEF_PTSIZE 80
  61. /*-public functions----------------------------------------------------------*/
  62. /* StatusInit
  63. *
  64. * - create window class
  65. */
  66. BOOL
  67. StatusInit(
  68. HANDLE hInstance
  69. )
  70. {
  71. WNDCLASS wc;
  72. BOOL resp;
  73. TEXTMETRIC tm = {0};
  74. HDC hDC;
  75. StatusCreateTools();
  76. wc.style = CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS;
  77. wc.lpfnWndProc = StatusWndProc;
  78. wc.cbClsExtra = 0;
  79. wc.cbWndExtra = sizeof(HANDLE);
  80. wc.hInstance = hInstance;
  81. wc.hIcon = NULL;
  82. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  83. wc.hbrBackground = hbrBackground;
  84. wc.lpszClassName = (LPSTR) "gdstatusclass";
  85. wc.lpszMenuName = NULL;
  86. resp = RegisterClass(&wc);
  87. hDC = GetDC(NULL);
  88. if (hDC)
  89. {
  90. InitDC(hDC);
  91. GetTextMetrics(hDC, &tm);
  92. ReleaseDC(NULL, hDC);
  93. }
  94. else
  95. {
  96. // arbitrary, whatever...
  97. tm.tmHeight = 14;
  98. tm.tmAveCharWidth = 5;
  99. }
  100. status_charheight = (int)(tm.tmHeight + tm.tmExternalLeading);
  101. status_charwidth = (int)tm.tmAveCharWidth;
  102. return(resp);
  103. }
  104. /*
  105. * create and show the window
  106. */
  107. HWND APIENTRY
  108. StatusCreate(
  109. HANDLE hInst,
  110. HWND hParent,
  111. INT_PTR id,
  112. LPRECT rcp,
  113. HANDLE hmem
  114. )
  115. {
  116. HWND hWnd;
  117. /* create a child window of status class */
  118. hWnd = CreateWindow("gdstatusclass",
  119. NULL,
  120. WS_CHILD | WS_VISIBLE,
  121. rcp->left,
  122. rcp->top,
  123. (rcp->right - rcp->left),
  124. (rcp->bottom - rcp->top),
  125. hParent,
  126. (HANDLE) id,
  127. hInst,
  128. (LPVOID) hmem);
  129. return(hWnd);
  130. }
  131. /* return default height of this window */
  132. int APIENTRY
  133. StatusHeight(
  134. HANDLE hmem
  135. )
  136. /* The window has a number of items which are arranged horizontally,
  137. so the window height is the maximum of the individual heights
  138. */
  139. {
  140. PILIST plist;
  141. int i;
  142. int sz;
  143. int maxsize = 0;
  144. plist = (PILIST) GlobalLock(hmem);
  145. if (plist != NULL) {
  146. for (i = 0; i<plist->nitems; i++) {
  147. sz = StatusCalcHeight(NULL, &plist->statels[i]);
  148. maxsize = max(sz, maxsize);
  149. }
  150. }
  151. GlobalUnlock(hmem);
  152. if (maxsize > 0) {
  153. return(maxsize + 4);
  154. } else {
  155. return(status_charheight + 4);
  156. }
  157. }
  158. /* alloc the plist struct and return handle to caller */
  159. HANDLE
  160. StatusAlloc(
  161. int nitems
  162. )
  163. {
  164. HANDLE hmem;
  165. PILIST pilist;
  166. LPSTR chp;
  167. hmem = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,
  168. sizeof(ILIST) + (sizeof(STATEL) * nitems));
  169. chp = GlobalLock(hmem);
  170. if (chp == NULL) {
  171. return(NULL);
  172. }
  173. pilist = (PILIST) chp;
  174. pilist->nitems = nitems;
  175. pilist->statels = (PSTATEL) &chp[sizeof(ILIST)];
  176. GlobalUnlock(hmem);
  177. return(hmem);
  178. }
  179. /* insert an item into the plist */
  180. BOOL
  181. StatusAddItem(
  182. HANDLE hmem,
  183. int itemnr,
  184. int type,
  185. int flags,
  186. int id,
  187. int width,
  188. LPSTR text
  189. )
  190. {
  191. PILIST pilist;
  192. PSTATEL pel;
  193. pilist = (PILIST) GlobalLock(hmem);
  194. if ((pilist == NULL) || (itemnr >= pilist->nitems)) {
  195. GlobalUnlock(hmem);
  196. return(FALSE);
  197. }
  198. pel = &pilist->statels[itemnr];
  199. pel->type = type;
  200. pel->flags = flags;
  201. pel->id = id;
  202. pel->width = width;
  203. if (text == NULL) {
  204. pel->text[0] = '\0';
  205. } else {
  206. lstrcpy(pel->text, text);
  207. }
  208. GlobalUnlock(hmem);
  209. return(TRUE);
  210. }
  211. /* ---- internal functions ------------------------------------------*/
  212. void
  213. InitDC(HDC hdc)
  214. {
  215. SetBkColor(hdc, RGB(192,192,192));
  216. SelectObject(hdc, hbrBackground);
  217. SelectObject(hdc, hFont);
  218. }
  219. void
  220. StatusCreateTools()
  221. {
  222. LOGFONT lf;
  223. HDC hdc;
  224. int scale;
  225. hbrBackground = CreateSolidBrush(RGB(192,192,192));
  226. hpenHilight = CreatePen(0, 1, RGB(255, 255, 255));
  227. hpenLowlight = CreatePen(0, 1, RGB(128, 128, 128));
  228. hpenNeutral = CreatePen(0, 1, RGB(192, 192, 192));
  229. hpenBlack = CreatePen(0, 1, RGB(0, 0, 0));
  230. hdc = GetDC(NULL);
  231. if (hdc)
  232. {
  233. scale = GetDeviceCaps(hdc, LOGPIXELSY);
  234. ReleaseDC(NULL, hdc);
  235. }
  236. else
  237. {
  238. // arbitrary, whatever...
  239. scale = 72;
  240. }
  241. lf.lfHeight = -MulDiv(DEF_PTSIZE, scale, 720);
  242. lf.lfWidth = 0;
  243. lf.lfEscapement = 0;
  244. lf.lfOrientation = 0;
  245. lf.lfWeight = FW_REGULAR;
  246. lf.lfItalic = 0;
  247. lf.lfUnderline = 0;
  248. lf.lfStrikeOut = 0;
  249. lf.lfCharSet = ANSI_CHARSET;
  250. lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  251. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  252. lf.lfQuality = PROOF_QUALITY;
  253. lf.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
  254. lf.lfFaceName[0] = '\0';
  255. #ifdef COMPLEX
  256. hFont = CreateFontIndirect(&lf);
  257. #else
  258. hFont = GetStockObject(SYSTEM_FONT);
  259. #endif
  260. }
  261. void
  262. StatusDeleteTools()
  263. {
  264. DeleteObject(hbrBackground);
  265. DeleteObject(hpenHilight);
  266. DeleteObject(hpenLowlight);
  267. DeleteObject(hpenBlack);
  268. DeleteObject(hpenNeutral);
  269. #ifdef COMPLEX
  270. DeleteObject(hFont);
  271. #endif
  272. }
  273. /* Main winproc for status windows
  274. *
  275. * handles create/destroy and paint requests
  276. */
  277. INT_PTR
  278. StatusWndProc(
  279. HWND hWnd,
  280. UINT message,
  281. WPARAM wParam,
  282. LPARAM lParam
  283. )
  284. {
  285. HANDLE hitems;
  286. PSTATEL ip;
  287. PILIST plist;
  288. CREATESTRUCT * cp;
  289. int i;
  290. HDC hDC;
  291. RECT rc;
  292. POINT pt;
  293. switch (message) {
  294. case WM_CREATE:
  295. cp = (CREATESTRUCT *) lParam;
  296. hitems = (HANDLE) cp->lpCreateParams;
  297. SetWindowLongPtr(hWnd, 0, (LONG_PTR)hitems);
  298. plist = (PILIST) GlobalLock(hitems);
  299. if (plist != NULL) {
  300. plist->selitem = -1;
  301. GlobalUnlock(hitems);
  302. }
  303. break;
  304. case WM_SIZE:
  305. hitems = (HANDLE) GetWindowLongPtr(hWnd, 0);
  306. plist = (PILIST) GlobalLock(hitems);
  307. if (plist != NULL) {
  308. StatusResize(hWnd, plist);
  309. GlobalUnlock(hitems);
  310. }
  311. break;
  312. case WM_PAINT:
  313. hitems = (HANDLE) GetWindowLongPtr(hWnd, 0);
  314. plist = (PILIST) GlobalLock(hitems);
  315. StatusPaint(hWnd, plist);
  316. GlobalUnlock(hitems);
  317. break;
  318. case WM_LBUTTONUP:
  319. hitems = (HANDLE) GetWindowLongPtr(hWnd, 0);
  320. plist = (PILIST) GlobalLock(hitems);
  321. pt.x = LOWORD(lParam);
  322. pt.y = HIWORD(lParam);
  323. if (plist == NULL) {
  324. break;
  325. }
  326. if (plist->selitem != -1) {
  327. ip = &plist->statels[plist->selitem];
  328. if (plist->isselected) {
  329. hDC = GetDC(hWnd);
  330. if (hDC)
  331. {
  332. InitDC(hDC);
  333. StatusButtonUp(hDC, ip);
  334. ReleaseDC(hWnd, hDC);
  335. }
  336. }
  337. plist->selitem = -1;
  338. ReleaseCapture();
  339. if (PtInRect(&ip->rc, pt)) {
  340. SendMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(ip->id, WM_LBUTTONUP), (LPARAM)hWnd);
  341. }
  342. }
  343. GlobalUnlock(hitems);
  344. break;
  345. case WM_LBUTTONDOWN:
  346. hitems = (HANDLE) GetWindowLongPtr(hWnd, 0);
  347. plist = (PILIST) GlobalLock(hitems);
  348. if (plist == NULL) {
  349. break;
  350. }
  351. pt.x = LOWORD(lParam);
  352. pt.y = HIWORD(lParam);
  353. if (plist->selitem == -1) {
  354. for (i = 0; i< plist->nitems; i++) {
  355. ip = &plist->statels[i];
  356. if (PtInRect(&ip->rc, pt)) {
  357. if (ip->type != SF_BUTTON) {
  358. break;
  359. }
  360. plist->selitem = i;
  361. SetCapture(hWnd);
  362. plist->isselected = TRUE;
  363. hDC = GetDC(hWnd);
  364. if (hDC)
  365. {
  366. InitDC(hDC);
  367. StatusButtonDown(hDC, ip);
  368. ReleaseDC(hWnd, hDC);
  369. }
  370. break;
  371. }
  372. }
  373. }
  374. GlobalUnlock(hitems);
  375. break;
  376. case WM_MOUSEMOVE:
  377. hitems = (HANDLE) GetWindowLongPtr(hWnd, 0);
  378. plist = (PILIST) GlobalLock(hitems);
  379. if (plist == NULL) {
  380. break;
  381. }
  382. pt.x = LOWORD(lParam);
  383. pt.y = HIWORD(lParam);
  384. if (plist->selitem != -1) {
  385. ip = &plist->statels[plist->selitem];
  386. if (PtInRect(&ip->rc, pt)) {
  387. if (!plist->isselected) {
  388. hDC = GetDC(hWnd);
  389. if (hDC)
  390. {
  391. InitDC(hDC);
  392. StatusButtonDown(hDC, ip);
  393. ReleaseDC(hWnd, hDC);
  394. }
  395. plist->isselected = TRUE;
  396. }
  397. } else {
  398. if (plist->isselected) {
  399. hDC = GetDC(hWnd);
  400. if (hDC)
  401. {
  402. InitDC(hDC);
  403. StatusButtonUp(hDC, ip);
  404. ReleaseDC(hWnd, hDC);
  405. }
  406. plist->isselected = FALSE;
  407. }
  408. }
  409. }
  410. GlobalUnlock(hitems);
  411. break;
  412. case WM_DESTROY:
  413. hitems = (HANDLE) GetWindowLongPtr(hWnd, 0);
  414. GlobalUnlock(hitems);
  415. GlobalFree(hitems);
  416. SetWindowLongPtr(hWnd, 0, 0);
  417. break;
  418. case SM_NEW:
  419. hitems = (HANDLE) GetWindowLongPtr(hWnd, 0);
  420. if (hitems != NULL) {
  421. GlobalFree(hitems);
  422. }
  423. hitems = (HANDLE) wParam;
  424. if (hitems == NULL) {
  425. SetWindowLongPtr(hWnd, 0, 0);
  426. InvalidateRect(hWnd, NULL, TRUE);
  427. break;
  428. }
  429. plist = (PILIST) GlobalLock(hitems);
  430. if (plist == NULL) {
  431. SetWindowLongPtr(hWnd, 0, 0);
  432. InvalidateRect(hWnd, NULL, TRUE);
  433. break;
  434. }
  435. plist->selitem = -1;
  436. StatusResize(hWnd, plist);
  437. GlobalUnlock(hitems);
  438. SetWindowLongPtr(hWnd, 0, (LONG_PTR)hitems);
  439. InvalidateRect(hWnd, NULL, TRUE);
  440. break;
  441. case SM_SETTEXT:
  442. hitems = (HANDLE) GetWindowLongPtr(hWnd, 0);
  443. if (hitems == NULL) {
  444. break;
  445. }
  446. plist = (PILIST) GlobalLock(hitems);
  447. ip = StatusGetItem(plist, (int)wParam);
  448. if (ip != NULL) {
  449. if (lParam == 0) {
  450. ip->text[0] = '\0';
  451. } else {
  452. My_mbsncpy(ip->text, (LPSTR) lParam, SF_MAXLABEL);
  453. ip->text[SF_MAXLABEL] = '\0';
  454. }
  455. /* if this is a variable width field, we need to redo
  456. * all size calcs in case the field width has changed.
  457. * in that case, we need to repaint the entire window
  458. * and not just this field - so set rc to indicate the
  459. * area to be redrawn.
  460. */
  461. if (ip->flags & SF_VAR) {
  462. StatusResize(hWnd, plist);
  463. GetClientRect(hWnd, &rc);
  464. RedrawWindow(hWnd, &rc, NULL,
  465. RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW);
  466. } else {
  467. /* instead of just invalidating the window, we can
  468. * force the window to be repainted now. This is
  469. * essential for status updates during a busy
  470. * loop when no messages are being processed,
  471. * but we should still update the user on what's
  472. * happening.
  473. */
  474. RedrawWindow(hWnd, &ip->rc, NULL,
  475. RDW_INVALIDATE|RDW_NOERASE|RDW_UPDATENOW);
  476. }
  477. }
  478. GlobalUnlock(hitems);
  479. break;
  480. default:
  481. return(DefWindowProc(hWnd, message, wParam, lParam));
  482. }
  483. return 0;
  484. }
  485. /*
  486. * position the labels and buttons within the status window */
  487. void
  488. StatusResize(HWND hWnd, PILIST iplistp)
  489. {
  490. RECT rc;
  491. int curpos_right, curpos_left;
  492. int height, width;
  493. int i;
  494. PSTATEL ip;
  495. if (iplistp == NULL) {
  496. return;
  497. }
  498. GetClientRect(hWnd, &rc);
  499. curpos_left = rc.left + status_charwidth / 2;
  500. curpos_right = rc.right - (status_charwidth / 2);
  501. /* loop through all items setting their position rects.
  502. * items are flagged as being left or right. We place them
  503. * in order starting at the left and the right, with a single
  504. * char's width between each item
  505. */
  506. for (i = 0; i < iplistp->nitems; i++) {
  507. ip = &iplistp->statels[i];
  508. width = StatusCalcWidth(hWnd, ip);
  509. height = StatusCalcHeight(hWnd, ip);
  510. ip->rc.top = (rc.bottom - height) / 2;
  511. ip->rc.bottom = ip->rc.top + height;
  512. /* see if this item fits. Items that partially fit
  513. * are placed reduced in size.
  514. */
  515. if (ip->flags & SF_LEFT) {
  516. if (curpos_left+width >= curpos_right) {
  517. /* doesn't completely fit-does it partly? */
  518. if ((curpos_left + 1) >= curpos_right) {
  519. /* no - this item does not fit */
  520. ip->rc.left = 0;
  521. ip->rc.right = 0;
  522. } else {
  523. /* partial fit */
  524. ip->rc.left = curpos_left;
  525. ip->rc.right = curpos_right - 1;
  526. curpos_left = curpos_right;
  527. }
  528. } else {
  529. /* complete fit */
  530. ip->rc.left = curpos_left;
  531. ip->rc.right = curpos_left + width;
  532. curpos_left += width + 1;
  533. }
  534. } else {
  535. /* same size check for right-aligned items */
  536. if (curpos_right-width <= curpos_left) {
  537. /* partial fit ? */
  538. if (curpos_right <= curpos_left+1) {
  539. ip->rc.left = 0;
  540. ip->rc.right = 0;
  541. } else {
  542. /* yes - partial fit */
  543. ip->rc.left = curpos_left + 1;
  544. ip->rc.right = curpos_right;
  545. curpos_right = curpos_left;
  546. }
  547. } else {
  548. /* complete fit */
  549. ip->rc.right = curpos_right;
  550. ip->rc.left = curpos_right - width;
  551. curpos_right -= (width + 1);
  552. }
  553. }
  554. }
  555. }
  556. void
  557. StatusPaint(HWND hWnd, PILIST iplistp)
  558. {
  559. RECT rc;
  560. HDC hDC;
  561. PAINTSTRUCT ps;
  562. int i;
  563. PSTATEL ip;
  564. HPEN hpenOld;
  565. GetClientRect(hWnd, &rc);
  566. hDC = BeginPaint(hWnd, &ps);
  567. InitDC(hDC);
  568. RaiseRect(hDC, &rc);
  569. if (iplistp == NULL) {
  570. EndPaint(hWnd, &ps);
  571. return;
  572. }
  573. for (i =0; i < iplistp->nitems; i++) {
  574. ip = &iplistp->statels[i];
  575. if (ip->rc.left == ip->rc.right) {
  576. continue;
  577. }
  578. if (ip->type == SF_STATIC) {
  579. if (ip->flags & SF_RAISE) {
  580. RaiseRect(hDC, &ip->rc);
  581. } else if (ip->flags & SF_LOWER) {
  582. LowerRect(hDC, &ip->rc);
  583. }
  584. rc = ip->rc;
  585. rc.left += (status_charwidth / 2);
  586. rc.right--;
  587. rc.top++;
  588. rc.bottom--;
  589. hpenOld = SelectObject(hDC, hpenNeutral);
  590. Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
  591. SelectObject(hDC, hpenOld);
  592. DrawText(hDC, ip->text, lstrlen(ip->text), &rc,
  593. DT_LEFT | DT_VCENTER);
  594. } else {
  595. StatusButtonUp(hDC, ip);
  596. }
  597. }
  598. EndPaint(hWnd, &ps);
  599. }
  600. void
  601. RaiseRect(HDC hDC, LPRECT rcp)
  602. {
  603. TopLeft(hDC, rcp, hpenHilight, FALSE);
  604. BottomRight(hDC, rcp, hpenLowlight, FALSE);
  605. }
  606. void
  607. LowerRect(HDC hDC, LPRECT rcp)
  608. {
  609. TopLeft(hDC, rcp, hpenLowlight, FALSE);
  610. BottomRight(hDC, rcp, hpenHilight, FALSE);
  611. }
  612. void
  613. StatusButtonUp(HDC hDC, PSTATEL ip)
  614. {
  615. RECT rc;
  616. HPEN hpenOld;
  617. TEXTMETRIC tm;
  618. rc = ip->rc;
  619. TopLeft(hDC, &rc, hpenBlack, TRUE);
  620. BottomRight(hDC, &rc, hpenBlack, FALSE);
  621. rc.top++;
  622. rc.bottom--;
  623. rc.left++;
  624. rc.right--;
  625. TopLeft(hDC, &rc, hpenHilight, FALSE);
  626. BottomRight(hDC, &rc, hpenLowlight, TRUE);
  627. rc.top++;
  628. rc.bottom--;
  629. rc.left++;
  630. rc.right--;
  631. BottomRight(hDC, &rc, hpenLowlight, TRUE);
  632. rc.bottom--;
  633. rc.right--;
  634. hpenOld = SelectObject(hDC, hpenNeutral);
  635. Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
  636. SelectObject(hDC, hpenOld);
  637. GetTextMetrics(hDC, &tm);
  638. rc.top += tm.tmExternalLeading;
  639. DrawText(hDC, ip->text, lstrlen(ip->text), &rc, DT_CENTER | DT_VCENTER);
  640. }
  641. void
  642. StatusButtonDown(HDC hDC, PSTATEL ip)
  643. {
  644. RECT rc;
  645. HPEN hpenOld;
  646. TEXTMETRIC tm;
  647. rc = ip->rc;
  648. TopLeft(hDC, &rc, hpenBlack, TRUE);
  649. BottomRight(hDC, &rc, hpenBlack, FALSE);
  650. rc.top++;
  651. rc.bottom--;
  652. rc.left++;
  653. rc.right--;
  654. TopLeft(hDC, &rc, hpenLowlight, TRUE);
  655. rc.top++;
  656. rc.left++;
  657. TopLeft(hDC, &rc, hpenNeutral, TRUE);
  658. rc.top++;
  659. rc.left++;
  660. TopLeft(hDC, &rc, hpenNeutral, TRUE);
  661. rc.top++;
  662. rc.left++;
  663. hpenOld = SelectObject(hDC, hpenNeutral);
  664. Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
  665. SelectObject(hDC, hpenOld);
  666. GetTextMetrics(hDC, &tm);
  667. rc.top += tm.tmExternalLeading;
  668. DrawText(hDC, ip->text, lstrlen(ip->text), &rc, DT_CENTER | DT_VCENTER);
  669. }
  670. void
  671. TopLeft(HDC hDC, LPRECT rcp, HPEN hpen, BOOL bCorners)
  672. {
  673. HPEN hpenOld;
  674. int x, y;
  675. hpenOld = SelectObject(hDC, hpen);
  676. x = rcp->right - 1;
  677. y = rcp->bottom;
  678. if (!bCorners) {
  679. x--;
  680. y--;
  681. }
  682. MoveToEx(hDC, x, rcp->top, NULL);
  683. LineTo(hDC, rcp->left, rcp->top);
  684. LineTo(hDC, rcp->left, y);
  685. SelectObject(hDC, hpenOld);
  686. }
  687. void
  688. BottomRight(HDC hDC, LPRECT rcp, HPEN hpen, BOOL bCorners)
  689. {
  690. HPEN hpenOld;
  691. int x, y;
  692. hpenOld = SelectObject(hDC, hpen);
  693. x = rcp->left - 1;
  694. y = rcp->top;
  695. if (!bCorners) {
  696. x++;
  697. y++;
  698. }
  699. MoveToEx(hDC, rcp->right-1, y, NULL);
  700. LineTo(hDC, rcp->right-1, rcp->bottom-1);
  701. LineTo(hDC, x, rcp->bottom-1);
  702. SelectObject(hDC, hpenOld);
  703. }
  704. PSTATEL
  705. StatusGetItem(PILIST plist, int id)
  706. {
  707. int i;
  708. if (plist == NULL) {
  709. return(NULL);
  710. }
  711. for (i = 0; i < plist->nitems; i++) {
  712. if (plist->statels[i].id == id) {
  713. return(&plist->statels[i]);
  714. }
  715. }
  716. return(NULL);
  717. }
  718. /*
  719. * calculate the width of a given field. This is the width in characters
  720. * multiplied by the average character width, plus a few units for
  721. * borders.
  722. *
  723. * if SF_VAR is set, this field size varies depending on the text, so
  724. * we use GetTextExtent for the field size. If SF_VAR is selected, the caller
  725. * can specify that the size is not to exceed the (width * avecharwidth)
  726. * size (using SF_SZMAX) or that it is not be less than it (SF_SZMIN).
  727. */
  728. int
  729. StatusCalcWidth(HWND hWnd, PSTATEL ip)
  730. {
  731. int ch_size, t_size;
  732. SIZE sz = {0};
  733. HDC hDC;
  734. ch_size = ip->width * status_charwidth;
  735. if (ip->flags & SF_VAR) {
  736. hDC = GetDC(hWnd);
  737. if (hDC)
  738. {
  739. InitDC(hDC);
  740. GetTextExtentPoint(hDC, ip->text, lstrlen(ip->text), &sz);
  741. ReleaseDC(hWnd, hDC);
  742. }
  743. t_size = sz.cx;
  744. /*
  745. * check this size against min/max size if
  746. * requested
  747. */
  748. if (ip->flags & SF_SZMIN) {
  749. if (ch_size > t_size) {
  750. t_size = ch_size;
  751. }
  752. }
  753. if (ip->flags & SF_SZMAX) {
  754. if (ch_size < t_size) {
  755. t_size = ch_size;
  756. }
  757. }
  758. ch_size = t_size;
  759. }
  760. if (ch_size != 0) {
  761. if (ip->type == SF_BUTTON) {
  762. return(ch_size+6);
  763. } else {
  764. return(ch_size+4);
  765. }
  766. } else {
  767. return(0);
  768. }
  769. }
  770. int
  771. StatusCalcHeight(HWND hWnd, PSTATEL ip)
  772. {
  773. int size;
  774. size = status_charheight;
  775. if (ip->type == SF_BUTTON) {
  776. return(size + 6);
  777. } else {
  778. return(size + 2);
  779. }
  780. }