source: trunk/src/helpers/cctl_toolbar.c@ 232

Last change on this file since 232 was 232, checked in by umoeller, 23 years ago

New toolbar control.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 38.7 KB
Line 
1
2/*
3 *@@sourcefile cctl_toolbar.c:
4 * implementation for the "tool bar" common control.
5 * See ctlCreateToolBar and ctl_fnwpToolbar.
6 *
7 * See comctl.c for an overview of the common controls.
8 *
9 * This file implements two window classes: a tool bar
10 * control (which is most conveniently used with
11 * ctlCreateStdWindow) and a tool button control as
12 * a replacement for the dull OS/2 pushbutton controls.
13 *
14 * This is new with V1.0.1 (2002-11-30) [umoeller].
15 *
16 * Note: Version numbering in this file relates to XWorkplace version
17 * numbering.
18 *
19 *@@header "helpers\comctl.h"
20 *@@added V1.0.1 (2002-11-30) [umoeller]
21 */
22
23/*
24 * Copyright (C) 1997-2002 Ulrich M”ller.
25 * This file is part of the "XWorkplace helpers" source package.
26 * This is free software; you can redistribute it and/or modify
27 * it under the terms of the GNU General Public License as published
28 * by the Free Software Foundation, in version 2 as it comes in the
29 * "COPYING" file of the XWorkplace main distribution.
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 */
35
36#define OS2EMX_PLAIN_CHAR
37 // this is needed for "os2emx.h"; if this is defined,
38 // emx will define PSZ as _signed_ char, otherwise
39 // as unsigned char
40
41#define INCL_WINWINDOWMGR
42#define INCL_WINFRAMEMGR
43#define INCL_WINSYS
44#define INCL_WINPOINTERS
45#define INCL_WININPUT
46#define INCL_WINBUTTONS
47
48#define INCL_GPIPRIMITIVES
49#define INCL_GPILOGCOLORTABLE
50#define INCL_GPIBITMAPS
51#define INCL_GPIPATHS
52#define INCL_GPIREGIONS
53#define INCL_GPIBITMAPS
54#include <os2.h>
55
56#include <stdlib.h>
57#include <stdio.h>
58#include <string.h>
59#include <setjmp.h> // needed for except.h
60#include <assert.h> // needed for except.h
61
62#include "setup.h" // code generation and debugging options
63
64#include "helpers\gpih.h"
65#include "helpers\linklist.h"
66#include "helpers\standards.h"
67#include "helpers\winh.h"
68
69#include "helpers\comctl.h"
70
71#pragma hdrstop
72
73/*
74 *@@category: Helpers\PM helpers\Window classes\Toolbars
75 * See cctl_toolbar.c.
76 */
77
78/* ******************************************************************
79 *
80 * Private definitions
81 *
82 ********************************************************************/
83
84/*
85 *@@ TBBUTTONDATA:
86 *
87 */
88
89typedef struct _TBBUTTONDATA
90{
91 XBUTTONDATA bd;
92 XBUTTONSTATE bs;
93} TBBUTTONDATA, *PTBBUTTONDATA;
94
95/*
96 *@@ TOOLBARDATA:
97 *
98 */
99
100typedef struct _TOOLBARDATA
101{
102 DEFWINDATA dwd;
103
104 HWND hwndControlsOwner;
105
106 LONG lSpacing,
107 lMaxControlCY;
108
109 LINKLIST llControls; // linked list of HWNDs for controls in toolbar
110
111 ULONG flReformat;
112 #define RFFL_HEIGHT 0x0001 // height changed, needs complete resize
113
114} TOOLBARDATA, *PTOOLBARDATA;
115
116#define TB_LEFT_SPACING 5
117#define TB_BOTTOM_SPACING 5
118
119#define TBB_BORDER 2
120
121#define TBB_TEXTSPACING 2
122
123/* ******************************************************************
124 *
125 * "Toolbar button" control
126 *
127 ********************************************************************/
128
129/*
130 *@@ ctlInitXButtonData:
131 *
132 */
133
134VOID ctlInitXButtonData(PXBUTTONDATA pbd, // in: button data
135 ULONG fl) // in: TBBS_* style flags
136{
137 if (fl & TBBS_BIGICON)
138 {
139 pbd->szlIconOrBitmap.cx = G_cxIcon;
140 pbd->szlIconOrBitmap.cy = G_cyIcon;
141 }
142 else if (fl & TBBS_MINIICON)
143 {
144 pbd->szlIconOrBitmap.cx = G_cxIcon / 2;
145 pbd->szlIconOrBitmap.cy = G_cyIcon / 2;
146 }
147 else if ( (fl & TBBS_BITMAP)
148 && (pbd->hptr)
149 )
150 {
151 BITMAPINFOHEADER2 bmih2;
152 bmih2.cbFix = sizeof(BITMAPINFOHEADER2);
153 GpiQueryBitmapInfoHeader(pbd->hptr,
154 &bmih2);
155 pbd->szlIconOrBitmap.cx = bmih2.cx;
156 pbd->szlIconOrBitmap.cy = bmih2.cy;
157 }
158}
159
160/*
161 *@@ ctlPaintTBButton:
162 * paints a tool bar button control. Can be called externally
163 * for just painting a button even if this is not really
164 * a window.
165 *
166 *@@added V0.9.13 (2001-06-21) [umoeller]
167 *@@changed V0.9.16 (2001-10-24) [umoeller]: fixed wrong hatch color and paint offset
168 *@@changed V0.9.16 (2001-10-28) [umoeller]: added bitmap support, fixed bad clip rectangle
169 *@@changed V0.9.20 (2002-08-04) [umoeller]: fixed button offset, depressed color
170 *@@changed V1.0.1 (2002-11-30) [umoeller]: moved this here from comctl.c, renamed
171 */
172
173VOID ctlPaintTBButton(HPS hps, // in: presentation space (RGB mode)
174 ULONG fl, // in: TBBS_* flags
175 PXBUTTONDATA pbd, // in: button data
176 PXBUTTONSTATE pbs) // in: button state
177{
178 LONG lBorder = 0,
179 lOfs = 0;
180 LONG lLeft,
181 lRight,
182 lColorMiddle = pbd->dwd.lcolBackground;
183 RECTL rclWin,
184 rclTemp;
185 POINTL ptl;
186
187 rclWin.xLeft = 0;
188 rclWin.yBottom = 0;
189 rclWin.xRight = pbd->dwd.szlWin.cx;
190 rclWin.yTop = pbd->dwd.szlWin.cy;
191 // make backup for later
192 memcpy(&rclTemp, &rclWin, sizeof(RECTL));
193
194 if (!(fl & TBBS_FLAT))
195 lBorder = TBB_BORDER;
196
197 gpihSwitchToRGB(hps);
198
199 if (pbs->fPaintButtonSunk)
200 {
201 // paint button "down":
202 lLeft = G_lcol3DDark;
203 lRight = G_lcol3DLight;
204 // add offset for icon painting at the bottom
205 lOfs += 1;
206 if (!lBorder)
207 lBorder = 1;
208 }
209 else
210 {
211 lLeft = G_lcol3DLight;
212 lRight = G_lcol3DDark;
213
214 if (!lBorder)
215 if (pbs->fMouseOver)
216 lBorder = 1;
217 }
218
219 if (lBorder)
220 {
221 // paint button border
222 // make rcl inclusive
223 rclWin.xRight--;
224 rclWin.yTop--;
225 gpihDraw3DFrame2(hps,
226 &rclWin, // inclusive
227 lBorder,
228 lLeft,
229 lRight);
230 rclWin.xRight++;
231 rclWin.yTop++;
232 }
233
234 if (fl & TBBS_BACKGROUND)
235 {
236 // now paint button middle
237 if (pbs->fPaintButtonSunk)
238 // make the depressed color darker
239 gpihManipulateRGB(&lColorMiddle,
240 .95);
241 else if ((fl & TBBS_HILITE) && (pbs->fMouseOver))
242 // make the mouse over color lighter
243 gpihManipulateRGB(&lColorMiddle,
244 1.05);
245
246 WinFillRect(hps,
247 &rclWin, // exclusive
248 lColorMiddle);
249 }
250
251 // calc x and y so that icon is centered in rectangle
252 ptl.x = ((pbd->dwd.szlWin.cx - pbd->szlIconOrBitmap.cx) / 2);
253 // center vertically only if we have no text
254 if (fl & TBBS_TEXT)
255 ptl.y = pbd->dwd.szlWin.cy - pbd->szlIconOrBitmap.cy - 2;
256 else
257 ptl.y = ((pbd->dwd.szlWin.cy - pbd->szlIconOrBitmap.cy) / 2);
258
259 if (fl & TBBS_INUSE)
260 {
261 // caller wants in-use (hatched) emphasis:
262 // draw a box then
263 POINTL ptl2;
264 ptl2.x = ptl.x - 2;
265 ptl2.y = ptl.y - 2;
266 GpiMove(hps,
267 &ptl2); // &ptl
268 // duh, typo V0.9.16 (2001-10-24) [umoeller]
269 GpiSetPattern(hps, PATSYM_DIAG1);
270 GpiSetColor(hps, RGBCOL_BLACK); // V0.9.16 (2001-10-24) [umoeller]
271 ptl2.x = ptl.x + pbd->szlIconOrBitmap.cx + 1; // inclusive!
272 ptl2.y = ptl.y + pbd->szlIconOrBitmap.cy + 1; // inclusive!
273 GpiBox(hps,
274 DRO_FILL,
275 &ptl2,
276 0,
277 0);
278 }
279
280 // make rcl inclusive
281 rclWin.xRight--;
282 rclWin.yTop--;
283 GpiIntersectClipRectangle(hps,
284 &rclWin); // inclusive!
285
286 if ( (pbd->hptr)
287 && (fl & (TBBS_BIGICON | TBBS_MINIICON | TBBS_BITMAP))
288 )
289 {
290 // RECTL rcl3;
291
292 // now paint icon
293 ptl.x += lOfs;
294 ptl.y -= lOfs;
295
296 /*
297 rcl3.xLeft = ptl.x;
298 rcl3.yBottom = ptl.y;
299 rcl3.xRight = ptl.x + pbd->szlIconOrBitmap.cx;
300 rcl3.yTop = ptl.y + pbd->szlIconOrBitmap.cy;
301 WinFillRect(hps, &rcl3, RGBCOL_GREEN);
302 */
303
304 if (fl & TBBS_BITMAP)
305 // V0.9.16 (2001-10-28) [umoeller]
306 WinDrawBitmap(hps,
307 pbd->hptr, // a bitmap really
308 NULL, // entire bitmap
309 &ptl,
310 0,
311 0,
312 DBM_NORMAL);
313 else
314 WinDrawPointer(hps,
315 // center this in remaining rectl
316 ptl.x,
317 ptl.y,
318 pbd->hptr,
319 (fl & TBBS_BIGICON)
320 ? DP_NORMAL
321 : DP_MINI);
322
323 rclTemp.yTop -= pbd->szlIconOrBitmap.cy;
324 }
325
326 if ( (pbd->dwd.pszText)
327 && (fl & TBBS_TEXT)
328 )
329 {
330 GpiSetColor(hps, pbd->dwd.lcolForeground);
331 rclTemp.yTop -= 2 * TBB_TEXTSPACING + lOfs;
332 rclTemp.xRight += 2 * lOfs; // twice the offset because we center horizontally
333 winhDrawFormattedText(hps,
334 &rclTemp,
335 pbd->dwd.pszText,
336 DT_CENTER | DT_TOP | DT_MNEMONIC | DT_WORDBREAK);
337 }
338}
339
340static const SYSCOLORSET scsToolbarButton =
341 {
342 TRUE, // inherit presparams
343 SYSCLR_BUTTONMIDDLE,
344 SYSCLR_MENUTEXT
345 };
346
347/*
348 *@@ BtnAutoSize:
349 *
350 */
351
352STATIC VOID BtnAutoSize(ULONG flStyle,
353 PTBBUTTONDATA pData)
354{
355 if (flStyle & TBBS_AUTORESIZE)
356 {
357 HPS hps;
358 if (hps = WinGetPS(pData->bd.dwd.hwnd))
359 {
360 ULONG ulBorder = 2;
361 if (!(flStyle & TBBS_FLAT))
362 ulBorder += TBB_BORDER;
363
364 pData->bd.dwd.szlWin.cx
365 = pData->bd.dwd.szlWin.cy
366 = 2 * ulBorder;
367
368 if (flStyle & (TBBS_BIGICON | TBBS_MINIICON | TBBS_BITMAP))
369 {
370 pData->bd.dwd.szlWin.cx += pData->bd.szlIconOrBitmap.cx;
371 pData->bd.dwd.szlWin.cy += pData->bd.szlIconOrBitmap.cy;
372
373 if (flStyle & TBBS_TEXT)
374 pData->bd.dwd.szlWin.cx += 2 * TBB_TEXTSPACING;
375 }
376
377 if (flStyle & TBBS_TEXT)
378 {
379 RECTL rcl = { 0, 0, 100, 100 };
380 LONG lMinX;
381 winhDrawFormattedText(hps,
382 &rcl,
383 pData->bd.dwd.pszText,
384 DT_TOP | DT_LEFT | DT_QUERYEXTENT);
385
386 lMinX = (rcl.xRight - rcl.xLeft) + 2 * TBB_TEXTSPACING;
387 STOREIFMAX(lMinX, pData->bd.dwd.szlWin.cx);
388 // pData->bd.dwd.rcl.xRight += (rcl.xRight - rcl.xLeft) + 2 * TBB_TEXTSPACING;
389 pData->bd.dwd.szlWin.cy += (rcl.yTop - rcl.yBottom) + 2 * TBB_TEXTSPACING;
390 }
391
392 WinSetWindowPos(pData->bd.dwd.hwnd,
393 0,
394 0,
395 0,
396 pData->bd.dwd.szlWin.cx,
397 pData->bd.dwd.szlWin.cy,
398 SWP_SIZE | SWP_NOADJUST);
399
400 WinReleasePS(hps);
401 }
402 }
403}
404
405/*
406 *@@ BtnCreate:
407 * implementation for WM_CREATE in ctl_fnwpToolbarButton.
408 */
409
410STATIC MRESULT BtnCreate(HWND hwndButton, MPARAM mp1, MPARAM mp2)
411{
412 PTBBUTTONDATA pData;
413 MRESULT mrc = 0;
414
415 if (!(pData = NEW(TBBUTTONDATA)))
416 mrc = (MRESULT)TRUE; // stop window creation
417 else
418 {
419 PCSZ pcszText = ((PCREATESTRUCT)mp2)->pszText;
420 PSZ p;
421
422 WinSetWindowPtr(hwndButton, QWL_USER + 1, pData);
423 ZERO(pData);
424
425 // initialize DEFWINDOWDATA
426 ctlInitDWD(hwndButton,
427 mp2,
428 &pData->bd.dwd,
429 WinDefWindowProc,
430 &scsToolbarButton);
431
432 if ( (pcszText)
433 && (*pcszText == '#')
434 )
435 {
436 pData->bd.hptr = atoi(pcszText + 1);
437 if (p = strchr(pcszText + 1, '#'))
438 pcszText = p + 1;
439 else
440 pcszText = NULL;
441 }
442
443 ctlInitXButtonData(&pData->bd,
444 ((PCREATESTRUCT)mp2)->flStyle);
445
446 if (pcszText)
447 {
448 pData->bd.dwd.pszText = strdup(pcszText);
449 if ( (((PCREATESTRUCT)mp2)->flStyle & TBBS_DROPMNEMONIC)
450 && (p = strchr(pData->bd.dwd.pszText, '~'))
451 )
452 memmove(p, p + 1, strlen(p));
453 }
454
455 BtnAutoSize(((PCREATESTRUCT)mp2)->flStyle,
456 pData);
457
458 if ( (((PCREATESTRUCT)mp2)->flStyle & TBBS_CHECKINITIAL)
459 && (((PCREATESTRUCT)mp2)->flStyle & (TBBS_CHECK | TBBS_RADIO))
460 )
461 pData->bs.fPaintButtonSunk = TRUE;
462 }
463
464 return mrc;
465}
466
467/*
468 *@@ BtnButton1Down:
469 * implementation for WM_BUTTON1DOWN in ctl_fnwpToolbarButton.
470 */
471
472STATIC MRESULT BtnButton1Down(HWND hwndButton)
473{
474 PTBBUTTONDATA pData;
475 if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
476 {
477 ULONG flStyle = winhQueryWindowStyle(hwndButton);
478
479 if (flStyle & WS_DISABLED)
480 WinAlarm(HWND_DESKTOP, WA_WARNING);
481 else
482 {
483 WinSetFocus(HWND_DESKTOP, hwndButton);
484
485 if (!pData->bs.fMouseCaptured)
486 {
487 // capture mouse events while the
488 // mouse button is down
489 WinSetCapture(HWND_DESKTOP, hwndButton);
490 pData->bs.fMouseCaptured = TRUE;
491 }
492
493 if (!pData->bs.fPaintButtonSunk)
494 {
495 // toggle state is still UP (i.e. button pressed
496 // for the first time): create menu
497 pData->bs.fPaintButtonSunk = TRUE;
498 WinInvalidateRect(hwndButton, NULL, FALSE);
499
500 if (flStyle & TBBS_CHECK)
501 // ignore the next button 1 up
502 pData->bs.fIgnoreMB1Up = TRUE;
503
504 } // end if (!pData->fButtonSunk)
505 }
506 }
507
508 return (MRESULT)TRUE; // processed
509}
510
511/*
512 *@@ ClickNotifyOwner:
513 *
514 */
515
516STATIC VOID ClickNotifyOwner(HWND hwndButton)
517{
518 HWND hwndOwner;
519
520 if (hwndOwner = WinQueryWindow(hwndButton, QW_OWNER))
521 {
522 ULONG flStyle = winhQueryWindowStyle(hwndButton);
523
524 if (flStyle & (TBBS_COMMAND | TBBS_SYSCOMMAND))
525 WinPostMsg(hwndOwner,
526 (flStyle & TBBS_SYSCOMMAND)
527 ? WM_SYSCOMMAND
528 : WM_COMMAND,
529 (MPARAM)WinQueryWindowUShort(hwndButton, QWS_ID),
530 MPFROM2SHORT(CMDSRC_PUSHBUTTON,
531 TRUE)); // pointer, not keyboard
532 else
533 ctlSendWmControl(hwndButton,
534 BN_CLICKED,
535 (MPARAM)hwndButton);
536 }
537}
538
539/*
540 *@@ BtnButton1Up:
541 * implementation for WM_BUTTON1UP in ctl_fnwpToolbarButton.
542 */
543
544STATIC MRESULT BtnButton1Up(HWND hwndButton)
545{
546 PTBBUTTONDATA pData;
547 if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
548 {
549 ULONG flStyle = winhQueryWindowStyle(hwndButton);
550
551 if (pData->bs.fMouseCaptured)
552 {
553 WinSetCapture(HWND_DESKTOP, NULLHANDLE);
554 pData->bs.fMouseCaptured = FALSE;
555 }
556
557 if (!(flStyle & WS_DISABLED))
558 {
559 pData->bs.fMB1Pressed = FALSE;
560
561 if (flStyle & TBBS_CHECK)
562 {
563 if (pData->bs.fIgnoreMB1Up)
564 pData->bs.fIgnoreMB1Up = FALSE;
565 else
566 pData->bs.fPaintButtonSunk = FALSE;
567
568 WinInvalidateRect(hwndButton, NULL, FALSE);
569
570 ClickNotifyOwner(hwndButton);
571 }
572 else if (flStyle & TBBS_RADIO)
573 {
574 WinSendMsg(hwndButton,
575 TBBM_CHECK,
576 (MPARAM)1,
577 0);
578
579 ClickNotifyOwner(hwndButton);
580 }
581 else
582 {
583 pData->bs.fPaintButtonSunk = FALSE;
584
585 ClickNotifyOwner(hwndButton);
586
587 WinInvalidateRect(hwndButton, NULL, FALSE);
588 }
589 }
590 }
591
592 return (MRESULT)TRUE; // processed
593}
594
595#define IGNORE_CHECK_MAGIC 0x87678a1d
596
597/*
598 *@@ UncheckOthers:
599 * gets called twice from BtnCheck for radio buttons
600 * to uncheck the others in the group.
601 */
602
603STATIC VOID BtnUncheckOthers(HWND hwndButton,
604 ULONG ulQW) // in: QW_PREV or QW_NEXT
605{
606 HWND hwnd = hwndButton;
607 CHAR szClass[50];
608
609 while (hwnd = WinQueryWindow(hwnd, ulQW))
610 {
611 if ( (!WinQueryClassName(hwnd, sizeof(szClass), szClass)
612 || (strcmp(szClass, WC_CCTL_TBBUTTON))
613 || (!(winhQueryWindowStyle(hwnd) & TBBS_RADIO)))
614 )
615 break;
616
617 WinSendMsg(hwnd,
618 TBBM_CHECK,
619 (MPARAM)FALSE,
620 (MPARAM)IGNORE_CHECK_MAGIC); // force uncheck without resending
621 }
622}
623
624/*
625 *@@ BtnCheck:
626 * implementation for TBBM_CHECK in ctl_fnwpToolbarButton.
627 */
628
629STATIC VOID BtnCheck(HWND hwndButton,
630 BOOL fCheck,
631 ULONG ulMagic)
632{
633 PTBBUTTONDATA pData;
634
635 if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
636 {
637 ULONG flStyle = winhQueryWindowStyle(hwndButton);
638
639 if ( (flStyle & TBBS_CHECK)
640 || (ulMagic == IGNORE_CHECK_MAGIC)
641 // magic code sent to radio tool bar buttons to
642 // force an uncheck without resending
643 )
644 {
645 pData->bs.fPaintButtonSunk = fCheck;
646 }
647 else if (flStyle & TBBS_RADIO)
648 {
649 BtnUncheckOthers(hwndButton, QW_PREV);
650 BtnUncheckOthers(hwndButton, QW_NEXT);
651
652 pData->bs.fPaintButtonSunk = TRUE;
653 }
654
655 WinInvalidateRect(hwndButton, NULL, FALSE);
656 }
657}
658
659/*
660 *@@ ctl_fnwpToolbarButton:
661 * window proc for the tool bar button control.
662 *
663 * This control is not at all based on the ugly OS/2 button
664 * control, but a complete rewrite. This supports a large
665 * variety of TBBS_* style flags which are useful in the
666 * context of a tool bar.
667 *
668 * The following styles are supported:
669 *
670 * -- WS_DISABLED @@todo halftone the display
671 *
672 * -- optionally one of TBBS_BIGICON, TBBS_MINIICON, or
673 * TBBS_BITMAP to paint a picture in the control
674 *
675 * -- optionally TBBS_TEXT; you can use this alone or
676 * together with one of the picture styles
677 *
678 * -- TBBS_CHECK: if set, button toggles between pressed
679 * and released on every click ("checkbox" style,
680 * even though it still looks as a button).
681 *
682 * -- TBBS_RADIO: if set, the button assumes it is part of
683 * a group and behaves like a radio button, that is, it
684 * automatically unchecks its sibling buttons which have
685 * this style too.
686 *
687 * -- TBBS_AUTORESIZE: if set, the button automatically
688 * resizes itself to the space it needs when its style
689 * or text changes.
690 *
691 * -- TBBS_HILITE: if set, the button hilites when mouse
692 * moves over it.
693 *
694 * -- TBBS_FLAT: if set, the button paints a border only
695 * if the mouse is moving over it; if not set, it
696 * always has a (thicker) border.
697 *
698 * -- TBBS_COMMAND, TBBS_SYSCOMMAND: if none of these are
699 * set, the button _sends_ WM_CONTROL with the standard
700 * button code BN_CLICKED to its owner when it is
701 * pressed. If TBBS_COMMAND is set, the button _posts_
702 * WM_COMMAND instead; if TBBS_SYSCOMMAND is set, the
703 * button posts WM_SYSCOMMAND instead.
704 *
705 * Note that this is different from the standard button
706 * behavior: even a tool bar button that does not have
707 * the TBBS_CHECK or TBBS_RADIO styles will only post
708 * WM_COMMAND if the TBBS_COMMAND style is set.
709 *
710 * There are two ways to set the icon or bitmap to be
711 * displayed with the control:
712 *
713 * -- Pass it with the window title on tool bar creation in
714 * the form "#handle#text", where "handle" is the decimal
715 * HPOINTER or HBITMAP and "text" is the actual button
716 * text. Note that this only works on creation, not with
717 * WinSetWindowText after creation.
718 *
719 * -- Send a XBBM_SETHANDLE message after button creation.
720 */
721
722MRESULT EXPENTRY ctl_fnwpToolbarButton(HWND hwndButton, ULONG msg, MPARAM mp1, MPARAM mp2)
723{
724 MRESULT mrc = 0;
725 PTBBUTTONDATA pData;
726
727 switch (msg)
728 {
729 case WM_CREATE:
730 mrc = BtnCreate(hwndButton, mp1, mp2);
731 break;
732
733 case WM_BUTTON1DOWN:
734 mrc = BtnButton1Down(hwndButton);
735 break;
736
737 case WM_BUTTON1UP:
738 mrc = BtnButton1Up(hwndButton);
739 break;
740
741 case WM_MOUSEENTER:
742 case WM_MOUSELEAVE:
743 if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
744 {
745 BOOL fMouseOver = (msg == WM_MOUSEENTER);
746 if (fMouseOver != pData->bs.fMouseOver)
747 {
748 pData->bs.fMouseOver = fMouseOver;
749 WinInvalidateRect(hwndButton, NULL, FALSE);
750 }
751 }
752 break;
753
754 case WM_PAINT:
755 {
756 HPS hps;
757 RECTL rcl;
758 POINTL ptl;
759 if (hps = WinBeginPaint(hwndButton, NULLHANDLE, &rcl))
760 {
761 if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
762 {
763 gpihSwitchToRGB(hps);
764 ctlPaintTBButton(hps,
765 winhQueryWindowStyle(hwndButton) | TBBS_BACKGROUND,
766 &pData->bd,
767 &pData->bs);
768 }
769
770 WinEndPaint(hps);
771 }
772 }
773 break;
774
775 /*
776 *@@ TBBM_CHECK:
777 * checks the given button. Effect depends on the
778 * button style:
779 *
780 * -- With TBBS_CHECK, this sets the button check
781 * state to (BOOL)mp1.
782 *
783 * -- With TBBS_CHECKGROUP, this sets the current
784 * button check state and unchecks neighboring
785 * buttons (siblings) that have the same style.
786 * mp1 is ignored.
787 *
788 * As opposed to a check in response to a mouse
789 * event, this does _not_ send out the BN_CLICKED
790 * notification.
791 */
792
793 case TBBM_CHECK:
794 BtnCheck(hwndButton, (BOOL)mp1, (ULONG)mp2);
795 break;
796
797 /*
798 *@@ TBBM_QUERYCHECK:
799 * returns the current check status of a button
800 * with TBBS_CHECK or TBBS_CHECKGROUP style
801 * as TRUE or FALSE.
802 *
803 * No parameters.
804 */
805
806 case TBBM_QUERYCHECK:
807 if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
808 mrc = (MRESULT)pData->bs.fPaintButtonSunk;
809 break;
810
811 case WM_DESTROY:
812 if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
813 {
814 FREE(pData->bd.dwd.pszText);
815 free(pData);
816 }
817 break;
818
819 default:
820 if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
821 mrc = ctlDefWindowProc(&pData->bd.dwd, msg, mp1, mp2);
822 }
823
824 return mrc;
825}
826
827/* ******************************************************************
828 *
829 * "Toolbar" control
830 *
831 ********************************************************************/
832
833static const SYSCOLORSET scsToolbar =
834 {
835 TRUE, // inherit presparams
836 SYSCLR_MENU,
837 SYSCLR_MENUTEXT
838 };
839
840/*
841 *@@ CreateToolbarControl:
842 *
843 */
844
845STATIC HWND CreateToolbarControl(PTOOLBARDATA pData,
846 PTOOLBARCONTROL pControl,
847 PLONG px,
848 PPRESPARAMS ppp)
849{
850 HWND hwndControl;
851
852 if (hwndControl = WinCreateWindow(pData->dwd.hwnd,
853 (PSZ)pControl->pcszClass,
854 (PSZ)pControl->pcszTitle,
855 pControl->flStyle,
856 *px,
857 TB_BOTTOM_SPACING,
858 pControl->cx,
859 pControl->cy,
860 pData->hwndControlsOwner,
861 HWND_TOP,
862 pControl->id,
863 NULL,
864 ppp))
865 {
866 *px += pControl->cx + pData->lSpacing;
867 }
868
869 return hwndControl;
870}
871
872/*
873 *@@ ReformatControls:
874 *
875 */
876
877STATIC VOID ReformatControls(HWND hwndToolBar)
878{
879 PTOOLBARDATA pData;
880 if (pData = (PTOOLBARDATA)WinQueryWindowPtr(hwndToolBar, QWL_USER + 1))
881 {
882 LONG x = TB_LEFT_SPACING;
883 PLISTNODE pNode;
884 LONG cControls;
885 PSWP paswp,
886 pswpThis;
887
888 if ( (cControls = lstCountItems(&pData->llControls))
889 && (paswp = (PSWP)malloc(sizeof(SWP) * cControls))
890 )
891 {
892 BOOL rc;
893
894 pswpThis = paswp;
895
896 FOR_ALL_NODES(&pData->llControls, pNode)
897 {
898 HWND hwnd = (HWND)pNode->pItemData;
899 SWP swp;
900 CHAR szClass[50];
901
902 WinQueryWindowPos(hwnd, &swp);
903
904 if ( (WinQueryClassName(hwnd, sizeof(szClass), szClass))
905 && (!strcmp(szClass, WC_CCTL_SEPARATOR))
906 )
907 {
908 pswpThis->cy = pData->lMaxControlCY;
909 pswpThis->fl = SWP_MOVE | SWP_SIZE;
910 }
911 else
912 {
913 pswpThis->cy = swp.cy;
914 pswpThis->fl = SWP_MOVE;
915 }
916
917 pswpThis->cx = swp.cx;
918 pswpThis->y = TB_BOTTOM_SPACING;
919 pswpThis->x = x;
920 pswpThis->hwndInsertBehind = HWND_BOTTOM;
921 pswpThis->hwnd = hwnd;
922
923 x += swp.cx + pData->lSpacing;
924
925 if (swp.cy > pData->lMaxControlCY)
926 {
927 pData->lMaxControlCY = swp.cy;
928 pData->flReformat = RFFL_HEIGHT;
929 }
930
931 pswpThis++;
932 }
933
934 rc = WinSetMultWindowPos(pData->dwd.hab,
935 paswp,
936 cControls);
937
938 free(paswp);
939 }
940 }
941}
942
943/*
944 *@@ TbAddControls:
945 *
946 */
947
948STATIC ULONG TbAddControls(PTOOLBARDATA pData,
949 ULONG cControls,
950 PTOOLBARCONTROL paControls,
951 LONG lIndex) // in: index before which to add entries; -1 means rightmost
952{
953 ULONG ul,
954 cCreated = 0;
955
956 LONG x = 0;
957 HWND hwndBefore;
958 SWP swp;
959
960 if (!lIndex)
961 x = TB_LEFT_SPACING;
962 else
963 {
964 if ( (lIndex > 0)
965 && (hwndBefore = (HWND)lstItemFromIndex(&pData->llControls,
966 lIndex))
967 && (WinQueryWindowPos(hwndBefore, &swp))
968 )
969 {
970 x = swp.x + swp.cx + pData->lSpacing;
971 }
972 }
973
974 if (x)
975 {
976 PPRESPARAMS ppp = NULL;
977
978 PCSZ pcszFont = winhQueryDefaultFont();
979 LONG lColor;
980
981 winhStorePresParam(&ppp,
982 PP_FONTNAMESIZE,
983 strlen(pcszFont) + 1,
984 (PVOID)pcszFont);
985
986 lColor = winhQueryPresColor2(pData->dwd.hwnd,
987 PP_BACKGROUNDCOLOR,
988 PP_BACKGROUNDCOLORINDEX,
989 FALSE,
990 scsToolbar.lBackIndex);
991 winhStorePresParam(&ppp,
992 PP_BACKGROUNDCOLOR,
993 sizeof(lColor),
994 &lColor);
995
996 lColor = winhQueryPresColor2(pData->dwd.hwnd,
997 PP_FOREGROUNDCOLOR,
998 PP_FOREGROUNDCOLORINDEX,
999 FALSE,
1000 scsToolbar.lForeIndex);
1001 winhStorePresParam(&ppp,
1002 PP_FOREGROUNDCOLOR,
1003 sizeof(lColor),
1004 &lColor);
1005
1006 // create controls
1007 for (ul = 0;
1008 ul < cControls;
1009 ++ul)
1010 {
1011 HWND hwndControl;
1012
1013 if (hwndControl = CreateToolbarControl(pData,
1014 &paControls[ul],
1015 &x,
1016 ppp))
1017 {
1018 lstInsertItemBefore(&pData->llControls,
1019 (PVOID)hwndControl,
1020 lIndex++);
1021 ++cCreated;
1022 }
1023 else
1024 break;
1025 }
1026
1027 if (ppp)
1028 free(ppp);
1029 }
1030
1031 pData->lMaxControlCY = 0;
1032 ReformatControls(pData->dwd.hwnd);
1033
1034 if (pData->flReformat & RFFL_HEIGHT)
1035 {
1036 if (WinQueryWindowULong(pData->dwd.hwnd, QWL_STYLE) & TBS_AUTORESIZE)
1037 {
1038 WinQueryWindowPos(pData->dwd.hwnd, &swp);
1039 WinSetWindowPos(pData->dwd.hwnd,
1040 0,
1041 0,
1042 0,
1043 swp.cx,
1044 pData->lMaxControlCY + 2 * TB_BOTTOM_SPACING,
1045 SWP_SIZE);
1046
1047 ReformatControls(pData->dwd.hwnd);
1048
1049 ctlPostWmControl(pData->dwd.hwnd,
1050 TBN_RESIZED,
1051 0);
1052
1053 pData->flReformat &= ~RFFL_HEIGHT;
1054 }
1055 }
1056
1057 return cCreated;
1058}
1059
1060/*
1061 *@@ TbCreate:
1062 *
1063 */
1064
1065STATIC MRESULT TbCreate(HWND hwndToolBar, MPARAM mp1, MPARAM mp2)
1066{
1067 PTOOLBARDATA pData;
1068 PTOOLBARCDATA ptbcd = (PTOOLBARCDATA)mp1;
1069
1070 if (!(pData = NEW(TOOLBARDATA)))
1071 return (MRESULT)TRUE; // stop window creation
1072
1073 WinSetWindowPtr(hwndToolBar, QWL_USER + 1, pData);
1074 ZERO(pData);
1075
1076 // initialize DEFWINDOWDATA
1077 ctlInitDWD(hwndToolBar,
1078 mp2,
1079 &pData->dwd,
1080 WinDefWindowProc,
1081 &scsToolbar);
1082
1083 pData->hwndControlsOwner = ptbcd->hwndControlsOwner;
1084 pData->lSpacing = 5;
1085 lstInit(&pData->llControls, FALSE);
1086
1087 if ( (ptbcd->cControls)
1088 && (ptbcd->patbc)
1089 )
1090 {
1091 TbAddControls(pData,
1092 ptbcd->cControls,
1093 ptbcd->patbc,
1094 0);
1095 }
1096
1097 return (MRESULT)FALSE;
1098}
1099
1100/*
1101 *@@ TbDestroy:
1102 *
1103 */
1104
1105STATIC VOID TbDestroy(HWND hwndToolBar)
1106{
1107 PTOOLBARDATA pData;
1108 if (pData = (PTOOLBARDATA)WinQueryWindowPtr(hwndToolBar, QWL_USER + 1))
1109 {
1110 PLISTNODE pNode;
1111 FOR_ALL_NODES(&pData->llControls, pNode)
1112 {
1113 WinDestroyWindow((HWND)pNode->pItemData);
1114 }
1115 lstClear(&pData->llControls);
1116 free(pData);
1117 }
1118}
1119
1120/*
1121 *@@ ctl_fnwpToolbar:
1122 * window proc for the tool bar class.
1123 *
1124 * The tool bar understands the following messages:
1125 *
1126 * -- TBM_ADDCONTROLS
1127 */
1128
1129MRESULT EXPENTRY ctl_fnwpToolbar(HWND hwndToolBar, ULONG msg, MPARAM mp1, MPARAM mp2)
1130{
1131 MRESULT mrc = 0;
1132 PTOOLBARDATA pData;
1133
1134 switch (msg)
1135 {
1136 case WM_CREATE:
1137 TbCreate(hwndToolBar, mp1, mp2);
1138 break;
1139
1140 /*
1141 *@@ TBM_ADDCONTROLS:
1142 * adds new controls to the tool bar.
1143 *
1144 * Parameters:
1145 *
1146 * -- PTOOLBARCONTROL mp1: array of TOOLBARCONTROL structs
1147 * which specify the windows to add to the tool bar.
1148 *
1149 * -- SHORT1FROMMP(mp2): number of items in that array
1150 * (not array size).
1151 *
1152 * -- SHORT2FROMMP(mp2): index where to add the new controls.
1153 * 0 means leftmost, 1 before the second item, and so on.
1154 * -1 means add rightmost.
1155 *
1156 * The tool bar will automatically repaint itself. If it
1157 * also has the TBS_AUTORESIZE window style, it will even
1158 * automatically resize itself and post its owner a
1159 * WM_CONTROL with TBN_RESIZED message so it can adjust
1160 * itself.
1161 */
1162
1163 case TBM_ADDCONTROLS:
1164 if (pData = (PTOOLBARDATA)WinQueryWindowPtr(hwndToolBar, QWL_USER + 1))
1165 {
1166 TbAddControls(pData,
1167 SHORT1FROMMP(mp2),
1168 (PTOOLBARCONTROL)mp1,
1169 SHORT2FROMMP(mp2));
1170 }
1171 break;
1172
1173 case WM_PAINT:
1174 {
1175 HPS hps;
1176 RECTL rcl;
1177 POINTL ptl;
1178 if (hps = WinBeginPaint(hwndToolBar, NULLHANDLE, &rcl))
1179 {
1180 gpihSwitchToRGB(hps);
1181 rcl.yBottom += 2;
1182 WinFillRect(hps,
1183 &rcl,
1184 winhQueryPresColor2(hwndToolBar,
1185 PP_BACKGROUNDCOLOR,
1186 PP_BACKGROUNDCOLORINDEX,
1187 FALSE,
1188 SYSCLR_MENU));
1189 ptl.x = 0;
1190 ptl.y = 0;
1191 GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONLIGHT, 0));
1192 GpiMove(hps, &ptl);
1193 ptl.x = rcl.xRight;
1194 GpiLine(hps, &ptl);
1195 ptl.x = 0;
1196 ptl.y = 1;
1197 GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONDARK, 0));
1198 GpiMove(hps, &ptl);
1199 ptl.x = rcl.xRight;
1200 GpiLine(hps, &ptl);
1201
1202 WinEndPaint(hps);
1203 }
1204 }
1205 break;
1206
1207 case WM_DESTROY:
1208 TbDestroy(hwndToolBar);
1209 break;
1210
1211 default:
1212 if (pData = (PTOOLBARDATA)WinQueryWindowPtr(hwndToolBar, QWL_USER + 1))
1213 mrc = ctlDefWindowProc(&pData->dwd, msg, mp1, mp2);
1214 }
1215
1216 return mrc;
1217}
1218
1219/*
1220 *@@ ctlRegisterToolbar:
1221 * this registers the tool bar window class (ctl_fnwpToolbar)
1222 * _and_ the tool bar button control (ctl_fnwpToolbarButton)
1223 * for an application. This is required before the tool bar
1224 * control can be used.
1225 */
1226
1227BOOL ctlRegisterToolbar(HAB hab)
1228{
1229 return ( WinRegisterClass(hab,
1230 WC_CCTL_TOOLBAR,
1231 ctl_fnwpToolbar,
1232 CS_SYNCPAINT | /* CS_CLIPSIBLINGS | */ CS_CLIPCHILDREN,
1233 sizeof(PVOID) * 2) // addt'l bytes to reserve:
1234 // one pointer for QWL_USER,
1235 // one more for instance data
1236 && WinRegisterClass(hab,
1237 WC_CCTL_TBBUTTON,
1238 ctl_fnwpToolbarButton,
1239 CS_SYNCPAINT | CS_CLIPSIBLINGS | CS_CLIPCHILDREN,
1240 sizeof(PVOID) * 2) // addt'l bytes to reserve:
1241 // one pointer for QWL_USER,
1242 // one more for instance data
1243 );
1244}
1245
1246/*
1247 *@@ ctlCreateToolBar:
1248 * type-safe wrapper around WinCreateWindow to create a tool bar.
1249 *
1250 * The easiest way to create a tool bar completely with the tools
1251 * is to pass them as an array of TOOLBARCONTROL structs here,
1252 * which simply specify the window classes to create. In most
1253 * cases, you will want to add tools of the WC_CCTL_TBBUTTON
1254 * and WC_SEPARATORLINE classes.
1255 *
1256 * Keep in mind to call ctlRegisterToolbar and ctlRegisterSeparatorLine
1257 * first, or window creation will fail.
1258 */
1259
1260HWND ctlCreateToolBar(HWND hwndParent, // in: parent of tool bar (e.g. frame)
1261 HWND hwndOwner, // in: owner of tool bar itself (e.g. frame)
1262 ULONG flStyle, // in: window style (WS_VISIBLE | TBS_* flags)
1263 HWND hwndControlsOwner, // in: owner for tool bar controls (e.g. frame client)
1264 ULONG cControls,
1265 PTOOLBARCONTROL patbc)
1266{
1267 TOOLBARCDATA tbcd;
1268 memset(&tbcd, 0, sizeof(tbcd));
1269 tbcd.cb = sizeof(tbcd);
1270 tbcd.hwndControlsOwner = hwndControlsOwner;
1271 tbcd.cControls = cControls;
1272 tbcd.patbc = patbc;
1273
1274 return WinCreateWindow(hwndParent,
1275 WC_CCTL_TOOLBAR,
1276 NULL,
1277 flStyle,
1278 0,
1279 0,
1280 0,
1281 0,
1282 hwndOwner,
1283 HWND_BOTTOM,
1284 FID_TOOLBAR,
1285 &tbcd,
1286 NULL);
1287}
Note: See TracBrowser for help on using the repository browser.