1 /*
2 * Motif
3 *
4 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
5 *
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
16 * details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
22 */
23 /*
24 * HISTORY
25 */
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30
31 #include <stdlib.h>
32 #include <Xm/AccTextT.h>
33 #include <Xm/ActivatableT.h>
34 #include <Xm/ArrowBG.h>
35 #include <Xm/CareVisualT.h>
36 #include <Xm/JoinSideT.h>
37 #include <Xm/NavigatorT.h>
38 #include <Xm/NotebookP.h>
39 #include <Xm/PushBGP.h>
40 #include <Xm/ScrollFrameT.h>
41 #include <Xm/SpinB.h>
42 #include <Xm/TextF.h>
43 #include <Xm/TraitP.h>
44 #include <Xm/TransltnsP.h>
45 #include <Xm/TravConT.h>
46 #include <Xm/UnhighlightT.h>
47 #include <Xm/VendorSEP.h>
48 #include <Xm/VaSimpleP.h>
49 #include "CareVisualTI.h"
50 #include "ColorI.h"
51 #include "GeoUtilsI.h"
52 #include "GMUtilsI.h"
53 #include "MessagesI.h"
54 #include "RegionI.h"
55 #include "RepTypeI.h"
56 #include "ScrollFramTI.h"
57 #include "XmI.h"
58
59 #define MESSAGE0 _XmMMsgNotebook_0000
60 #define MESSAGE1 _XmMMsgMotif_0001
61
62
63 /* Under SunOS /usr/include/sys/sysmacros.h (included by types.h) */
64 /* thoughtfully grabs part of our name space. */
65 #ifdef major
66 #undef major
67 #endif
68
69 #ifdef minor
70 #undef minor
71 #endif
72
73
74 /*****************************************************************************
75 * *
76 * constants & useful macros *
77 * *
78 *****************************************************************************/
79
80
81 /* names of notebook internal children */
82 #define MAJOR_TAB_NEXT_NAME "MajorTabScrollerNext"
83 #define MAJOR_TAB_PREV_NAME "MajorTabScrollerPrevious"
84 #define MINOR_TAB_NEXT_NAME "MinorTabScrollerNext"
85 #define MINOR_TAB_PREV_NAME "MinorTabScrollerPrevious"
86 #define PAGE_SCROLLER_NAME "PageScroller"
87 #define NB_TEXT_FIELD_NAME "NBTextField"
88
89 /* status values for notebook.scroller_status */
90 #define DEFAULT_NONE 0 /* default is not created yet */
91 #define DEFAULT_CREATE 1 /* default being created */
92 #define DEFAULT_USED 2 /* default is being used */
93 #define DEFAULT_GONE 3 /* default is destroyed */
94
95 /* Notebook position value */
96 #define LEFT 0
97 #define RIGHT 1
98 #define TOP 2
99 #define BOTTOM 4
100
101 /* tab traversal value */
102 #define _HOME 0
103 #define _END 1
104 #define _NEXT 2
105 #define _PREVIOUS 3
106 #define _FIRST_VISIBLE 4 /* For KNextTab/KPrevTab, scrolling */
107 #define _LAST_VISIBLE 5 /* For tab scrolling */
108 #define _CURRENT_VISIBLE 6 /* For tab group traversal */
109
110 /* status values for drawing minor tabs */
111 #define TAB_DRAW 0 /* tab is to be drawn */
112 #define TAB_DRAWING 1 /* tab is being drawn */
113 #define TAB_DRAWN 2 /* tab has been drawn */
114
115
116 /* XmNotebook default values */
117 #define FIRST_PAGE_NUMBER_DEFAULT 1
118 #define BACK_PAGE_NUMBER_DEFAULT 2
119 #define BACK_PAGE_SIZE_DEFAULT 8
120 #define BINDING_WIDTH_DEFAULT 25
121 #define MARGIN_WIDTH_DEFAULT 0
122 #define MARGIN_HEIGHT_DEFAULT 0
123 #define MAJOR_TAB_SPACING_DEFAULT 3
124 #define MINOR_TAB_SPACING_DEFAULT 3
125 #define TAB_SCROLLER_WIDTH_DEFAULT 20
126 #define TAB_SCROLLER_HEIGHT_DEFAULT 20
127 #define NOTEBOOK_MINIMUM_WIDTH 16
128 #define NOTEBOOK_MINIMUM_HEIGHT 16
129 #define MIN_DRAWABLE_SPIRAL_SIZE 6
130
131 /* macros */
132
133 #define NB_IS_CHILD_NONE(x) \
134 ((unsigned char)x == XmNONE)
135 #define NB_IS_CHILD_PAGE(x) \
136 ((unsigned char)x == XmPAGE)
137 #define NB_IS_CHILD_MAJOR(x) \
138 ((unsigned char)x == XmMAJOR_TAB)
139 #define NB_IS_CHILD_MINOR(x) \
140 ((unsigned char)x == XmMINOR_TAB)
141 #define NB_IS_CHILD_TAB(x) \
142 (((unsigned char)x == XmMAJOR_TAB) \
143 || ((unsigned char)x == XmMINOR_TAB))
144 #define NB_IS_CHILD_STATUS(x) \
145 ((unsigned char)x == XmSTATUS_AREA)
146 #define NB_IS_CHILD_PAGE_SCROLLER(x) \
147 ((unsigned char)x == XmPAGE_SCROLLER)
148 #define NB_IS_CHILD_MAJOR_SCROLLER(x) \
149 (((unsigned char)x == XmMAJOR_TAB_SCROLLER) \
150 || ((unsigned char)x == XmTAB_SCROLLER))
151 #define NB_IS_CHILD_MINOR_SCROLLER(x) \
152 (((unsigned char)x == XmMINOR_TAB_SCROLLER) \
153 || ((unsigned char)x == XmTAB_SCROLLER))
154
155
156 /* Layout defines */
157 #define NB_IS_VISIBLE(w) \
158 ((XtIsManaged(w) && \
159 ((w)->core.x > -(int)((w)->core.width + (w)->core.border_width * 2)) && \
160 ((w)->core.y > -(int)((w)->core.height + (w)->core.border_width * 2))))
161
162 #define NB_IS_HIDDEN(w) \
163 (((w)->core.x <= -(int)((w)->core.width + (w)->core.border_width * 2)) && \
164 ((w)->core.y <= -(int)((w)->core.height + (w)->core.border_width * 2)))
165
166 #define NB_ENFORCE_SIGN(s,x) ((s) > 0 ? (x) : -(x))
167
168 /* Fixed placement of non-top minor tabs */
169 #define NB_MINOR_TAB_STEP(x) ((x) /2)
170
171 /* Max dimension of major tab area, i.e.,
172 max of tab and tab scroller dimension */
173 #define NB_MAJOR_MAX(n,x,y) (MAX((x), (y)))
174 /* MAX(0, (n)->notebook.shadow_thickness - (n)->notebook.back_page_size)) */
175
176 /* Max dimension of minor tab area, i.e.,
177 max of tab (minus fixed placement) and
178 tab scroller dimension */
179 #define NB_MINOR_MAX(n,x,y) \
180 (MAX((int)((x) - NB_MINOR_TAB_STEP((n)->notebook.back_page_size)),(int)(y)))
181 /* MAX(0, (n)->notebook.shadow_thickness - (n)->notebook.back_page_size)) */
182
183
184 /* Retrieve trait defines */
185 #define NB_SCROLL_FRAME(x) \
186 ((XmScrollFrameTrait)XmeTraitGet((XtPointer)XtClass((Widget)(x)), \
187 XmQTscrollFrame))
188
189 #define NB_ACTIVATABLE(x) \
190 ((XmActivatableTrait)XmeTraitGet((XtPointer)XtClass((Widget)(x)), \
191 XmQTactivatable))
192
193 #define NB_NAVIGATOR(x) \
194 ((XmNavigatorTrait)XmeTraitGet((XtPointer)XtClass((Widget)(x)), \
195 XmQTnavigator))
196
197 #define NB_JOINSIDE(x) \
198 ((XmJoinSideTrait)XmeTraitGet((XtPointer)XtClass((Widget)(x)), \
199 XmQTjoinSide))
200
201
202 /* Is trait defines */
203 #define NB_IS_CHILD_ACTIVATABLE(x) \
204 (((XmeTraitGet((XtPointer)XtClass(x),XmQTactivatable)) != NULL) \
205 ? True : False)
206
207 #define NB_IS_CHILD_NAVIGATOR(x) \
208 (((XmeTraitGet((XtPointer)XtClass(x),XmQTnavigator)) != NULL) \
209 ? True : False)
210
211 #define NB_IS_CHILD_JOINSIDE(x) \
212 (((XmeTraitGet((XtPointer)XtClass(x),XmQTjoinSide)) != NULL) \
213 ? True : False)
214
215 #define NB_IS_CHILD_ACCESSTEXTUAL(x) \
216 (((XmeTraitGet((XtPointer)XtClass(x),XmQTaccessTextual)) != NULL) \
217 ? True : False)
218
219
220 #define NotebookConstraint(w) \
221 (&((XmNotebookConstraintPtr) (w)->core.constraints)->notebook)
222
223
224 /* If the original dimension is negative, then offset the original
225 position by that negative amount and make it the new position. Also
226 make the new dimension be the positive original dimension. So for
227 instance, if the x value is 20 and the width is -10, then make the x
228 value be 10 and the width be positive 10. If the original dimension
229 is not negative, then just set the new values to be the same as the
230 old values. */
231
232 #define ADJUST_NEGATIVE_DIMENSION(orig_pos, orig_dim, new_pos, new_dim) \
233 if (orig_dim < 0) \
234 { \
235 new_pos = orig_pos + orig_dim; \
236 new_dim = (Dimension) (orig_dim * -1) ; \
237 } \
238 else \
239 { \
240 new_pos = orig_pos; \
241 new_dim = (Dimension) orig_dim; \
242 }
243
244
245 #define manager_translations _XmNotebook_manager_translations
246
247
248 /*****************************************************************************
249 * *
250 * global variables *
251 * *
252 *****************************************************************************/
253
254
255 static XtAccelerators TabAcceleratorsParsed;
256
257
258 /*****************************************************************************
259 * *
260 * Static function declarations *
261 * *
262 *****************************************************************************/
263
264
265
266 /* synthetic hook */
267 static void GetDefaultFrameBackground(
268 Widget g,
269 int offset,
270 XrmValue *value) ;
271 static void GetDefaultBackPageBackground(
272 Widget g,
273 int offset,
274 XrmValue *value) ;
275 static void GetDefaultBackPagePos(
276 Widget w,
277 int offset,
278 XrmValue *value) ;
279 static void FromOrientationPixels(
280 Widget w,
281 int offset,
282 XtArgVal *value) ;
283 static XmImportOperator ToOrientationPixels(
284 Widget w,
285 int offset,
286 XtArgVal *value) ;
287 static void FromOrientationOppositePixels(
288 Widget w,
289 int offset,
290 XtArgVal *value) ;
291 static XmImportOperator ToOrientationOppositePixels(
292 Widget w,
293 int offset,
294 XtArgVal *value) ;
295 /* core class method */
296 static void ClassInitialize (
297 void) ;
298 static void ClassPartInitialize(
299 WidgetClass wc) ;
300 static void Initialize(
301 Widget rw,
302 Widget nw,
303 ArgList args,
304 Cardinal *num) ;
305 static void Destroy(
306 Widget w) ;
307 static void Resize(
308 Widget w) ;
309 static void Redisplay(
310 Widget w,
311 XEvent *e,
312 Region region) ;
313 static Boolean SetValues(
314 Widget ow,
315 Widget rw,
316 Widget nw,
317 ArgList args,
318 Cardinal *num) ;
319 static XtGeometryResult QueryGeometry(
320 Widget w,
321 XtWidgetGeometry *intended,
322 XtWidgetGeometry *desired) ;
323 static XtGeometryResult GeometryManager(
324 Widget instigator,
325 XtWidgetGeometry *desired,
326 XtWidgetGeometry *reply) ;
327 static void ChangeManaged(
328 Widget w) ;
329 static void InsertChild(
330 Widget child) ;
331 static void DeleteChild(
332 Widget child) ;
333 static void ConstraintInitialize(
334 Widget req,
335 Widget new_w,
336 ArgList args,
337 Cardinal *num) ;
338 static void CreateTabScrollers(
339 XmNotebookWidget nb) ;
340 static void SetVisualConfig(
341 XmNotebookWidget nb) ;
342 static Boolean UpdateJoinSide(
343 XmNotebookWidget nb,
344 Widget child,
345 unsigned char child_type,
346 Dimension shadow_thickness) ;
347 static void UpdateJoinSideChildren(
348 XmNotebookWidget nb,
349 Dimension shadow_thickness) ;
350 static void SetPageScroller(
351 XmNotebookWidget nb) ;
352 static void LayoutChildren(
353 XmNotebookWidget nb,
354 Widget instigator) ;
355 static void LayoutPages(
356 XmNotebookWidget nb,
357 Widget instigator) ;
358 static void LayoutMajorTabs(
359 XmNotebookWidget nb,
360 Widget instigator) ;
361 static void LayoutMinorTabs(
362 XmNotebookWidget nb,
363 Widget instigator) ;
364 static void ResetTopPointers(
365 XmNotebookWidget nb,
366 unsigned char reason,
367 int scroll) ;
368 static void GetFrameGCs(
369 XmNotebookWidget nb) ;
370 static void GetBackpageGCs(
371 XmNotebookWidget nb) ;
372 static void DrawBinding(
373 XmNotebookWidget nb,
374 XExposeEvent *event,
375 Region region) ;
376 static void MakeSpiralPixmap(
377 XmNotebookWidget nb,
378 Dimension width,
379 Dimension height) ;
380 static void DrawPixmapBinding(
381 XmNotebookWidget nb,
382 Dimension x,
383 Dimension y,
384 Dimension width,
385 Dimension height,
386 Pixmap pixmap) ;
387 static void DrawFrameShadow(
388 XmNotebookWidget nb,
389 XExposeEvent *event,
390 Region region) ;
391 static void DrawBackPages(
392 XmNotebookWidget nb,
393 XExposeEvent *event,
394 Region region) ;
395 static Boolean NewPreferredGeometry(
396 XmNotebookWidget nb,
397 Widget instigator,
398 XtWidgetGeometry *desired,
399 XtWidgetGeometry *preferred) ;
400 static void AdjustGeometry(
401 XmNotebookWidget nb,
402 Widget instigator,
403 XtWidgetGeometry *desired) ;
404 static Boolean SetLastPageNumber (
405 XmNotebookWidget nb,
406 int last_page_number) ;
407 static Boolean AssignDefaultPageNumber(
408 XmNotebookWidget nb) ;
409 static Boolean ConstraintSetValues(
410 Widget old_w,
411 Widget req,
412 Widget new_w,
413 ArgList args,
414 Cardinal *num) ;
415 static void SetActiveChildren(
416 XmNotebookWidget nb) ;
417 static void RepositionChild(
418 XmNotebookWidget nb,
419 Widget child) ;
420 static void SortChildren(
421 XmNotebookWidget nb) ;
422 static int GetNextAvailPageNum(
423 XmNotebookWidget nb,
424 int last) ;
425 static Widget GetChildWidget(
426 XmNotebookWidget nb,
427 int page_number,
428 unsigned char child_type) ;
429 static void GotoPage(
430 XmNotebookWidget nb,
431 int page_number,
432 XEvent *event,
433 int reason) ;
434 static void ShowChild(
435 Widget child,
436 Widget instigator,
437 int x,
438 int y,
439 int width,
440 int height) ;
441 static void HideChild(
442 Widget child,
443 Widget instigator) ;
444 static void HideShadowedTab(
445 XmNotebookWidget nb,
446 Widget child) ;
447 static void FlipTabs(
448 Widget w,
449 XtPointer data,
450 XtPointer call_data) ;
451 static void TabPressed(
452 Widget w,
453 XtPointer data,
454 XtPointer call_data) ;
455 static void TraverseTab(
456 Widget w,
457 XEvent *event,
458 String *params,
459 Cardinal *num_params) ;
460 static Widget GetNextTab(
461 XmNotebookWidget nb,
462 unsigned char child_type,
463 int page_number,
464 unsigned char direction) ;
465 static Boolean MaxIsRightUp(
466 XmNotebookWidget nb,
467 unsigned char child_type) ;
468 static void ScrollFrameInit(
469 Widget w,
470 XtCallbackProc moveCB,
471 Widget scrollable) ;
472 static Boolean ScrollFrameGetInfo(
473 Widget w,
474 Cardinal *dimension,
475 Widget **nav_list,
476 Cardinal *num_nav_list) ;
477 static void AddNavigator(
478 Widget w,
479 Widget nav,
480 Mask dimMask) ;
481 static void RemoveNavigator(
482 Widget w,
483 Widget nav) ;
484 static void PageMove(
485 Widget w,
486 XtPointer data,
487 XtPointer call_data) ;
488 static Widget RedirectTraversal(
489 Widget old_focus,
490 Widget new_focus,
491 unsigned int focus_policy,
492 XmTraversalDirection direction,
493 unsigned int pass) ;
494 static void UpdateNavigators(
495 XmNotebookWidget nb) ;
496 static GC GetUnhighlightGC(
497 Widget w,
498 Widget child) ;
499 static unsigned char GetDefaultBackPagePosAgain(
500 Widget w);
501
502
503 /*****************************************************************************
504 * *
505 * Action Records *
506 * *
507 *****************************************************************************/
508
509
510 static XtActionsRec tab_actions_list[] =
511 {
512 {"TraverseTab", TraverseTab},
513 };
514
515
516 /*****************************************************************************
517 * *
518 * Resources *
519 * *
520 *****************************************************************************/
521
522
523 static XtResource resources[] =
524 {
525 {
526 XmNcurrentPageNumber,
527 XmCCurrentPageNumber,
528 XmRInt,
529 sizeof(int),
530 XtOffsetOf(XmNotebookRec, notebook.current_page_number),
531 XmRImmediate,
532 (XtPointer)XmUNSPECIFIED_PAGE_NUMBER
533 },
534 {
535 XmNfirstPageNumber,
536 XmCFirstPageNumber,
537 XmRInt,
538 sizeof(int),
539 XtOffsetOf(XmNotebookRec, notebook.first_page_number),
540 XmRImmediate,
541 (XtPointer)FIRST_PAGE_NUMBER_DEFAULT,
542 },
543 {
544 XmNlastPageNumber,
545 XmCLastPageNumber,
546 XmRInt,
547 sizeof(int),
548 XtOffsetOf(XmNotebookRec, notebook.last_page_number),
549 XmRImmediate,
550 (XtPointer)XmUNSPECIFIED_PAGE_NUMBER
551 },
552 {
553 XmNorientation,
554 XmCOrientation,
555 XmROrientation,
556 sizeof(unsigned char),
557 XtOffsetOf(XmNotebookRec, notebook.orientation),
558 XmRImmediate,
559 (XtPointer)XmHORIZONTAL
560 },
561 {
562 XmNframeBackground,
563 XmCFrameBackground,
564 XmRPixel,
565 sizeof(Pixel),
566 XtOffsetOf(XmNotebookRec, notebook.frame_background),
567 XmRCallProc,
568 (XtPointer) GetDefaultFrameBackground
569 },
570 {
571 XmNbackPagePlacement,
572 XmCBackPagePlacement,
573 XmRScrollBarPlacement,
574 sizeof(unsigned char),
575 XtOffsetOf(XmNotebookRec, notebook.back_page_pos),
576 XmRCallProc,
577 (XtPointer)GetDefaultBackPagePos
578 },
579 {
580 XmNbackPageNumber,
581 XmCBackPageNumber,
582 XmRCardinal,
583 sizeof(Cardinal),
584 XtOffsetOf(XmNotebookRec, notebook.back_page_number),
585 XmRImmediate,
586 (XtPointer)BACK_PAGE_NUMBER_DEFAULT
587 },
588 {
589 XmNbackPageSize,
590 XmCBackPageSize,
591 XmRHorizontalDimension,
592 sizeof(Dimension),
593 XtOffsetOf(XmNotebookRec, notebook.back_page_size),
594 XmRImmediate,
595 (XtPointer)BACK_PAGE_SIZE_DEFAULT
596 },
597 {
598 XmNbackPageForeground,
599 XmCBackPageForeground,
600 XmRPixel,
601 sizeof(Pixel),
602 XtOffsetOf(XmNotebookRec, notebook.back_page_foreground),
603 XmRCallProc,
604 (XtPointer)_XmForegroundColorDefault
605 },
606 {
607 XmNbackPageBackground,
608 XmCBackPageBackground,
609 XmRPixel,
610 sizeof(Pixel),
611 XtOffsetOf(XmNotebookRec, notebook.back_page_background),
612 XmRCallProc,
613 (XtPointer)GetDefaultBackPageBackground
614 },
615 {
616 XmNbindingType,
617 XmCBindingType,
618 XmRBindingType,
619 sizeof(unsigned char),
620 XtOffsetOf(XmNotebookRec, notebook.binding_type),
621 XmRImmediate,
622 (XtPointer)XmSPIRAL
623 },
624 {
625 XmNbindingPixmap,
626 XmCBindingPixmap,
627 XmRDynamicPixmap,
628 sizeof(Pixmap),
629 XtOffsetOf(XmNotebookRec, notebook.binding_pixmap),
630 XmRImmediate,
631 (XtPointer)XmUNSPECIFIED_PIXMAP
632 },
633 {
634 XmNbindingWidth,
635 XmCBindingWidth,
636 XmRHorizontalDimension,
637 sizeof(Dimension),
638 XtOffsetOf(XmNotebookRec, notebook.binding_width),
639 XmRImmediate,
640 (XtPointer)BINDING_WIDTH_DEFAULT
641 },
642 {
643 XmNinnerMarginWidth,
644 XmCInnerMarginWidth,
645 XmRHorizontalDimension,
646 sizeof(Dimension),
647 XtOffsetOf(XmNotebookRec, notebook.margin_width),
648 XmRImmediate,
649 (XtPointer)MARGIN_WIDTH_DEFAULT
650 },
651 {
652 XmNinnerMarginHeight,
653 XmCInnerMarginHeight,
654 XmRVerticalDimension,
655 sizeof(Dimension),
656 XtOffsetOf(XmNotebookRec, notebook.margin_height),
657 XmRImmediate,
658 (XtPointer)MARGIN_HEIGHT_DEFAULT
659 },
660 {
661 XmNmajorTabSpacing,
662 XmCMajorTabSpacing,
663 XmRHorizontalDimension,
664 sizeof(Dimension),
665 XtOffsetOf(XmNotebookRec, notebook.major_spacing),
666 XmRImmediate,
667 (XtPointer)MAJOR_TAB_SPACING_DEFAULT
668 },
669 {
670 XmNminorTabSpacing,
671 XmCMinorTabSpacing,
672 XmRHorizontalDimension,
673 sizeof(Dimension),
674 XtOffsetOf(XmNotebookRec, notebook.minor_spacing),
675 XmRImmediate,
676 (XtPointer)MINOR_TAB_SPACING_DEFAULT
677 },
678 {
679 XmNframeShadowThickness,
680 XmCShadowThickness,
681 XmRHorizontalDimension,
682 sizeof(Dimension),
683 XtOffsetOf(XmNotebookRec, notebook.shadow_thickness),
684 XmRCallProc,
685 (XtPointer) _XmSetThickness
686 },
687 {
688 XmNpageChangedCallback,
689 XmCCallback,
690 XmRCallback,
691 sizeof(XtCallbackList),
692 XtOffsetOf(XmNotebookRec, notebook.page_change_callback),
693 XmRPointer,
694 (XtPointer)NULL
695 }
696 };
697
698
699 static XtResource constraint_resources[] =
700 {
701 {
702 XmNnotebookChildType,
703 XmCNotebookChildType,
704 XmRNotebookChildType,
705 sizeof(unsigned char),
706 XtOffsetOf(XmNotebookConstraintRec, notebook.child_type),
707 XmRImmediate,
708 (XtPointer)XmNONE
709 },
710 {
711 XmNpageNumber,
712 XmCPageNumber,
713 XmRInt,
714 sizeof(int),
715 XtOffsetOf(XmNotebookConstraintRec, notebook.page_number),
716 XmRImmediate,
717 (XtPointer)XmUNSPECIFIED_PAGE_NUMBER
718 },
719 {
720 XmNresizable,
721 XmCResizable,
722 XmRBoolean,
723 sizeof(Boolean),
724 XtOffsetOf(XmNotebookConstraintRec, notebook.resizable),
725 XmRImmediate,
726 (XtPointer)True
727 }
728 };
729
730
731 static XmSyntheticResource syn_resources[] =
732 {
733 {
734 XmNbackPageSize,
735 sizeof(Dimension),
736 XtOffsetOf(XmNotebookRec, notebook.back_page_size),
737 XmeFromHorizontalPixels,XmeToHorizontalPixels
738 },
739 {
740 XmNbindingWidth,
741 sizeof(Dimension),
742 XtOffsetOf(XmNotebookRec, notebook.binding_width),
743 FromOrientationPixels,ToOrientationPixels
744 },
745 {
746 XmNinnerMarginWidth,
747 sizeof(Dimension),
748 XtOffsetOf(XmNotebookRec, notebook.margin_width),
749 XmeFromHorizontalPixels,XmeToHorizontalPixels
750 },
751 {
752 XmNinnerMarginHeight,
753 sizeof(Dimension),
754 XtOffsetOf(XmNotebookRec, notebook.margin_height),
755 XmeFromVerticalPixels,XmeToVerticalPixels
756 },
757 {
758 XmNmajorTabSpacing,
759 sizeof(Dimension),
760 XtOffsetOf(XmNotebookRec, notebook.major_spacing),
761 FromOrientationOppositePixels,ToOrientationOppositePixels
762 },
763 {
764 XmNminorTabSpacing,
765 sizeof(Dimension),
766 XtOffsetOf(XmNotebookRec, notebook.minor_spacing),
767 FromOrientationPixels,ToOrientationPixels
768 },
769 {
770 XmNframeShadowThickness,
771 sizeof(Dimension),
772 XtOffsetOf(XmNotebookRec, notebook.shadow_thickness),
773 XmeFromHorizontalPixels,XmeToHorizontalPixels
774 }
775 };
776
777
778 /*****************************************************************************
779 * *
780 * Notebook class record definition *
781 * *
782 *****************************************************************************/
783
784
785 externaldef(xmnotebookclassrec) XmNotebookClassRec xmNotebookClassRec =
786 {
787 /* core class record */
788 {
789 (WidgetClass)&xmManagerClassRec, /* superclass */
790 "XmNotebook", /* class_name */
791 sizeof(XmNotebookRec), /* widget_size */
792 ClassInitialize, /* class_initialize */
793 ClassPartInitialize, /* class_part_initialize */
794 FALSE, /* class_inited */
795 Initialize, /* initialize */
796 NULL, /* initialize_hook */
797 XtInheritRealize, /* realize */
798 tab_actions_list, /* actions */
799 XtNumber(tab_actions_list), /* num_actions */
800 resources, /* resources */
801 XtNumber(resources), /* num_resources */
802 NULLQUARK, /* xrm_class */
803 TRUE, /* compress_motion */
804 XtExposeCompressMaximal, /* compress_exposure */
805 TRUE, /* compress enterleave */
806 TRUE, /* visible_interest */
807 Destroy, /* destroy */
808 Resize, /* resize */
809 Redisplay, /* expose */
810 SetValues, /* set_values */
811 NULL, /* set_values_hook */
812 XtInheritSetValuesAlmost, /* set_value_almost */
813 NULL, /* get_values_hook */
814 NULL, /* accept focus */
815 XtVersion, /* current version */
816 NULL, /* callback private */
817 XtInheritTranslations, /* translation table */
818 QueryGeometry, /* query_geometry */
819 NULL, /* display_accelerator */
820 NULL /* extension */
821 },
822 /* Composite class record */
823 {
824 GeometryManager, /* childrens geometry_manager */
825 ChangeManaged, /* change_managed */
826 InsertChild, /* insert_child */
827 DeleteChild, /* delete_child */
828 NULL /* extension */
829 },
830 /* Constraint class record */
831 {
832 constraint_resources, /* constraint resource */
833 XtNumber(constraint_resources), /* number of constraints */
834 sizeof(XmNotebookConstraintRec), /* size of constraint */
835 ConstraintInitialize, /* initialization */
836 NULL, /* destroy proc */
837 ConstraintSetValues, /* set_values proc */
838 NULL /* extension */
839 },
840 /* Manager class record */
841 {
842 manager_translations, /* translations */
843 syn_resources, /* syn_resources */
844 XtNumber(syn_resources), /* num_syn_resources */
845 NULL, /* get_cont_resources */
846 0, /* num_get_cont_resources */
847 XmInheritParentProcess, /* parent_process */
848 NULL /* extension */
849 },
850 /* Notebook class record */
851 {
852 NULL /* unused */
853 }
854 };
855
856
857 externaldef(xmnotebookwidgetclass) WidgetClass xmNotebookWidgetClass =
858 (WidgetClass) &xmNotebookClassRec;
859
860
861 /* Trait record for Notebook scrollFrame */
862 static XmConst XmScrollFrameTraitRec notebookSFT =
863 {
864 1, /* version */
865 ScrollFrameInit, /* initialize */
866 ScrollFrameGetInfo, /* get trait info */
867 AddNavigator, /* add navigator method */
868 RemoveNavigator, /* remove navigator method */
869 NULL /* update original geometry */
870 };
871
872
873 /* Trait record for Notebook traversalControl */
874 static XmConst XmTraversalControlTraitRec notebookTCT =
875 {
876 0, /* version */
877 RedirectTraversal /* redirect */
878 };
879
880
881 /* Trait record for Notebook specifyUnhighlight */
882 static XmConst XmSpecifyUnhighlightTraitRec notebookSUT =
883 {
884 0, /* version */
885 GetUnhighlightGC /* getUnhighlightGC */
886 };
887
888
889
890
891 /*****************************************************************************
892 * *
893 * Core method functions *
894 * *
895 *****************************************************************************/
896
897
898 /*- ClassInitialize ---------------------------------------------------------
899
900 This routine is invoked only once.
901
902 -----------------------------------------------------------------------------*/
903 static void
ClassInitialize(void)904 ClassInitialize(void)
905 {
906 /* Parse the default accelerator table */
907 TabAcceleratorsParsed =
908 XtParseAcceleratorTable( _XmNotebook_TabAccelerators );
909 }
910
911
912 /*- ClassPartInitialize -----------------------------------------------------
913
914 Set up the fast subclassing for the widget and install traits
915
916 -----------------------------------------------------------------------------*/
917 static void
ClassPartInitialize(WidgetClass wc)918 ClassPartInitialize (
919 WidgetClass wc)
920 {
921 _XmFastSubclassInit(wc, XmNOTEBOOK_BIT);
922
923 XmeTraitSet((XtPointer)wc,XmQTscrollFrame,(XtPointer)¬ebookSFT);
924 XmeTraitSet((XtPointer)wc,XmQTtraversalControl,(XtPointer)¬ebookTCT);
925 XmeTraitSet((XtPointer)wc,XmQTspecifyUnhighlight,(XtPointer)¬ebookSUT);
926
927 }
928
929
930 /*- Initialize --------------------------------------------------------------
931
932 Initialize method
933
934 -----------------------------------------------------------------------------*/
935
936 /*ARGSUSED*/
937 static void
Initialize(Widget rw,Widget nw,ArgList args,Cardinal * num)938 Initialize (
939 Widget rw, /* unused */
940 Widget nw,
941 ArgList args, /* unused */
942 Cardinal *num) /* unused */
943 {
944 XmNotebookWidget new_w = (XmNotebookWidget)nw;
945 XmScrollFrameTrait scroll_frameT;
946
947 /* XmNaccelerators */
948 new_w->core.accelerators = TabAcceleratorsParsed;
949
950 /* XmNorientation */
951 if (!XmRepTypeValidValue(XmRID_ORIENTATION,new_w->notebook.orientation,nw))
952 new_w->notebook.orientation = XmHORIZONTAL;
953
954 /* XmNbackPagePlacement */
955 if (!XmRepTypeValidValue(XmRID_SCROLL_BAR_PLACEMENT,
956 new_w->notebook.back_page_pos, nw))
957 new_w->notebook.back_page_pos = GetDefaultBackPagePosAgain(nw);
958
959 /* XmNbindingType */
960 if (!XmRepTypeValidValue(XmRID_BINDING_TYPE,
961 new_w->notebook.binding_type, nw))
962 new_w->notebook.binding_type = XmSOLID;
963
964 /* set tab and binding positions */
965 SetVisualConfig(new_w);
966
967 /* page number resources */
968
969 /* fix BUX 1183 in notebook widget, the real_back_page_number is used
970 * for division, however it is never set unless the back_page_number
971 * changed (in SetValues).
972 */
973 ASSIGN_MIN(new_w->notebook.real_back_page_number,
974 (Dimension)(new_w->notebook.back_page_size /2));
975 ASSIGN_MAX(new_w->notebook.real_back_page_number, 1);
976
977 if (new_w->notebook.current_page_number == XmUNSPECIFIED_PAGE_NUMBER)
978 new_w->notebook.current_page_number = new_w->notebook.first_page_number;
979 if (new_w->notebook.last_page_number == XmUNSPECIFIED_PAGE_NUMBER)
980 {
981 new_w->notebook.last_page_number = new_w->notebook.first_page_number;
982 new_w->notebook.dynamic_last_page_num = True;
983 }
984 else
985 new_w->notebook.dynamic_last_page_num = False;
986 new_w->notebook.last_alloc_num = new_w->notebook.first_page_number;
987
988 /* intialize variables for layouting tabs */
989 new_w->notebook.first_major = NULL;
990 new_w->notebook.old_top_major = NULL;
991 new_w->notebook.top_major = NULL;
992 new_w->notebook.last_major = NULL;
993 new_w->notebook.first_minor = NULL;
994 new_w->notebook.old_top_minor = NULL;
995 new_w->notebook.top_minor = NULL;
996 new_w->notebook.last_minor = NULL;
997 new_w->notebook.constraint_child = NULL;
998
999 /* shadow thickness state for current page major and minor tab */
1000 new_w->notebook.major_shadow_thickness = (Dimension) 0;
1001 new_w->notebook.minor_shadow_thickness = (Dimension) 0;
1002 new_w->notebook.in_setshadow = False;
1003 new_w->notebook.major_shadow_child = NULL;
1004 new_w->notebook.minor_shadow_child = NULL;
1005
1006 /* other misc. variables */
1007 new_w->notebook.which_tab = XmMAJOR_TAB;
1008 new_w->notebook.scroller_status = DEFAULT_NONE;
1009 new_w->notebook.need_scroller = XmNONE;
1010 new_w->notebook.scroller = NULL;
1011 new_w->notebook.scroller_child = NULL;
1012 new_w->notebook.in_callback = False;
1013 new_w->notebook.frame_gc = NULL;
1014 new_w->notebook.binding_gc = NULL;
1015 new_w->notebook.background_gc = NULL;
1016 new_w->notebook.foreground_gc = NULL;
1017 new_w->notebook.spiral_pixmap = XmUNSPECIFIED_PIXMAP;
1018
1019
1020 /* initialize the scroll_frame and change_managed flags */
1021 new_w->notebook.scroll_frame_data = NULL;
1022 new_w->notebook.first_change_managed = True;
1023
1024 /* initialize the scrollFrame with move callback (subclass trait check) */
1025
1026 if (((scroll_frameT=NB_SCROLL_FRAME(nw)) != NULL)
1027 && (scroll_frameT->init != NULL) )
1028 scroll_frameT->init(nw, PageMove, nw);
1029
1030 /* creating GCs */
1031 GetFrameGCs(new_w);
1032 GetBackpageGCs(new_w);
1033
1034 /* create tab scrollers */
1035 CreateTabScrollers(new_w);
1036 SetPageScroller(new_w);
1037
1038 }
1039
1040
1041 /*- Destroy -----------------------------------------------------------------
1042
1043 Destroy the widget and its children
1044
1045 -----------------------------------------------------------------------------*/
1046 static void
Destroy(Widget w)1047 Destroy (
1048 Widget w)
1049 {
1050 XmNotebookWidget nb = (XmNotebookWidget)w;
1051
1052 /* release all GCs */
1053 if (nb->notebook.frame_gc)
1054 XtReleaseGC(w, nb->notebook.frame_gc);
1055 if (nb->notebook.binding_gc)
1056 XtReleaseGC(w,nb->notebook.binding_gc);
1057 if (nb->notebook.foreground_gc)
1058 XtReleaseGC(w,nb->notebook.foreground_gc);
1059 if (nb->notebook.background_gc)
1060 XtReleaseGC(w,nb->notebook.background_gc);
1061
1062 /* release spiral pixmap */
1063 if (nb->notebook.spiral_pixmap != XmUNSPECIFIED_PIXMAP
1064 && nb->notebook.spiral_pixmap != XmNONE)
1065 XFreePixmap(XtDisplay(w), nb->notebook.spiral_pixmap);
1066
1067 /* release scroll frame data */
1068 if (nb->notebook.scroll_frame_data != NULL)
1069 XtFree((char*)nb->notebook.scroll_frame_data);
1070 }
1071
1072
1073 /*- Resize -----------------------------------------------------------------
1074
1075 Resize the widget
1076
1077 -----------------------------------------------------------------------------*/
1078 static void
Resize(Widget w)1079 Resize (
1080 Widget w)
1081 {
1082 XmNotebookWidget nb = (XmNotebookWidget)w;
1083
1084 /* Adjust notebook children sizes based on notebook size */
1085 AdjustGeometry(nb, NULL, NULL);
1086
1087 /* Layout children based on notebook sizes */
1088 LayoutChildren(nb, NULL);
1089
1090 if (XtIsRealized(w))
1091 XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,True);
1092 }
1093
1094
1095 /*- Redisplay ---------------------------------------------------------------
1096
1097 Method for expose event
1098
1099 -----------------------------------------------------------------------------*/
1100 static void
Redisplay(Widget w,XEvent * e,Region region)1101 Redisplay (
1102 Widget w,
1103 XEvent *e,
1104 Region region)
1105 {
1106 XmNotebookWidget nb = (XmNotebookWidget)w;
1107 XExposeEvent *event = (XExposeEvent *)e;
1108 Widget child; /* fix for CR8959, hack for CR9805 */
1109 int i; /* fix for CR8959, hack for CR9805 */
1110 int total_major_tabs,total_minor_tabs;
1111 XmNotebookConstraint nc;
1112 total_major_tabs = 0;
1113 for (i = 0; i < nb->composite.num_children; i++)
1114 {
1115 child = nb->composite.children[i];
1116 nc = NotebookConstraint(child);
1117 if (NB_IS_CHILD_MAJOR(nc->child_type))
1118 total_major_tabs++;
1119 }
1120 if (total_major_tabs > 0 )
1121 {
1122 XtManageChild(nb->notebook.prev_major);
1123 XtManageChild(nb->notebook.next_major);
1124 }
1125 else
1126 {
1127 XtUnmanageChild(nb->notebook.prev_major);
1128 XtUnmanageChild(nb->notebook.next_major);
1129 }
1130 total_minor_tabs = 0;
1131 for (i = 0; i < nb->composite.num_children; i++)
1132 {
1133 child = nb->composite.children[i];
1134 nc = NotebookConstraint(child);
1135 if (NB_IS_CHILD_MAJOR(nc->child_type))
1136 total_minor_tabs++;
1137 }
1138 if (total_minor_tabs > 0 )
1139 {
1140 XtManageChild(nb->notebook.prev_minor);
1141 XtManageChild(nb->notebook.next_minor);
1142 }
1143 else
1144 {
1145 XtUnmanageChild(nb->notebook.prev_minor);
1146 XtUnmanageChild(nb->notebook.next_minor);
1147 }
1148 /* draw the background */
1149 DrawBackPages(nb, event, region);
1150 DrawBinding(nb, event, region);
1151 DrawFrameShadow(nb, event, region);
1152
1153 /* display gadgets */
1154 XmeRedisplayGadgets(w,e,region);
1155
1156 /* Work-around due to PushBG not updating border highlight
1157 -- to be removed when PushBG is fixed, see CR9805 */
1158 for (i=0; i < nb->composite.num_children; i++)
1159 {
1160 child = nb->composite.children[i];
1161 if ( (NB_IS_CHILD_TAB(NotebookConstraint(child)->child_type))
1162 && (NotebookConstraint(child)->active)
1163 && (XmIsPushButtonGadget((child))))
1164 {
1165 (*(xmPushButtonGadgetClassRec.gadget_class.border_unhighlight))((child));
1166 }
1167 }
1168 }
1169
1170
1171 /*- SetValues ---------------------------------------------------------------
1172
1173 Set notebook widget resources
1174
1175 -----------------------------------------------------------------------------*/
1176 /*ARGSUSED*/
1177 static Boolean
SetValues(Widget ow,Widget rw,Widget nw,ArgList args,Cardinal * num)1178 SetValues (
1179 Widget ow,
1180 Widget rw, /* unused */
1181 Widget nw,
1182 ArgList args, /* unused */
1183 Cardinal *num) /* unused */
1184 {
1185 XmNotebookWidget old = (XmNotebookWidget) ow;
1186 XmNotebookWidget new_w = (XmNotebookWidget) nw;
1187 Boolean redraw = False;
1188 Boolean updateJoin = False;
1189 Boolean updateVisual = False;
1190 Boolean relayout = False;
1191 Mask visualFlag = NoVisualChange;
1192
1193 /* XmNorientation */
1194 if (new_w->notebook.orientation != old->notebook.orientation)
1195 {
1196 if (!XmRepTypeValidValue(XmRID_ORIENTATION,
1197 new_w->notebook.orientation, nw))
1198 new_w->notebook.orientation = old->notebook.orientation;
1199 }
1200
1201 /* XmNbackPagePlacement */
1202 if (new_w->notebook.back_page_pos != old->notebook.back_page_pos)
1203 {
1204 if (!XmRepTypeValidValue(XmRID_SCROLL_BAR_PLACEMENT,
1205 new_w->notebook.back_page_pos, nw))
1206 new_w->notebook.back_page_pos = old->notebook.back_page_pos;
1207 }
1208
1209 /* XmNbindingType */
1210 if (new_w->notebook.binding_type != old->notebook.binding_type)
1211 {
1212 if (!XmRepTypeValidValue(XmRID_BINDING_TYPE,
1213 new_w->notebook.binding_type, nw))
1214 new_w->notebook.binding_type = old->notebook.binding_type;
1215 }
1216
1217 /* XmNcurrentPageNumber */
1218 /* current page must be in the page number range */
1219 ASSIGN_MAX(new_w->notebook.current_page_number,
1220 new_w->notebook.first_page_number);
1221 ASSIGN_MIN(new_w->notebook.current_page_number,
1222 new_w->notebook.last_page_number);
1223
1224 /* XmNlastPageNumber */
1225 /* set static last page number, if the last page number is set */
1226 if (new_w->notebook.last_page_number != old->notebook.last_page_number)
1227 new_w->notebook.dynamic_last_page_num = False;
1228
1229 /* XmNfirstPageNumber */
1230 /* re-determine active children, if page number range has been changed */
1231 if (new_w->notebook.first_page_number != old->notebook.first_page_number
1232 || new_w->notebook.last_page_number != old->notebook.last_page_number)
1233 {
1234 /* Update navigators, unless GotoPage() will */
1235 if (new_w->notebook.current_page_number ==
1236 old->notebook.current_page_number)
1237 UpdateNavigators(new_w);
1238 SetActiveChildren(new_w);
1239 }
1240
1241 /* if XmNcurrentPageNumber is changed, go to the new page */
1242 if (new_w->notebook.current_page_number !=
1243 old->notebook.current_page_number)
1244 {
1245 int page_number;
1246
1247 page_number = new_w->notebook.current_page_number;
1248 new_w->notebook.current_page_number = old->notebook.current_page_number;
1249 GotoPage(new_w, page_number, NULL, XmCR_NONE);
1250 }
1251
1252 /*
1253 * Notebook visuals
1254 */
1255
1256 /* XmNorientation, XmNbackPagePlacement */
1257 if (new_w->notebook.orientation != old->notebook.orientation
1258 || new_w->notebook.back_page_pos != old->notebook.back_page_pos)
1259 {
1260 updateVisual = True;
1261 updateJoin = True;
1262 }
1263
1264 /* XmNframeShadowThickness */
1265 if (new_w->notebook.shadow_thickness != old->notebook.shadow_thickness)
1266 updateJoin = True;
1267
1268 /* XmNbackPageNumber */
1269 if (new_w->notebook.back_page_number != old->notebook.back_page_number)
1270 {
1271 /* set the real back page number */
1272 new_w->notebook.real_back_page_number =
1273 new_w->notebook.back_page_number;
1274 ASSIGN_MIN(new_w->notebook.real_back_page_number,
1275 (Dimension)(new_w->notebook.back_page_size /2));
1276 ASSIGN_MAX(new_w->notebook.real_back_page_number, 1);
1277 if (new_w->notebook.real_back_page_number !=
1278 old->notebook.real_back_page_number)
1279 redraw = True;
1280 }
1281
1282 /* XmNframeBackground */
1283 if (new_w->notebook.frame_background != old->notebook.frame_background
1284 || new_w->manager.foreground != old->manager.foreground)
1285 {
1286 GetFrameGCs(new_w);
1287 visualFlag |= (VisualHighlightColor|VisualHighlightPixmap);
1288 }
1289
1290 /* XmNbackPageBackground, XmNbackPageForeground */
1291 if (new_w->notebook.back_page_background !=
1292 old->notebook.back_page_background
1293 || new_w->notebook.back_page_foreground !=
1294 old->notebook.back_page_foreground)
1295 GetBackpageGCs(new_w);
1296
1297 /* Set new size, if necessary */
1298 if (XtIsRealized((Widget)new_w) &&
1299 (new_w->notebook.orientation != old->notebook.orientation
1300 || new_w->notebook.back_page_pos != old->notebook.back_page_pos
1301 || new_w->notebook.back_page_size != old->notebook.back_page_size
1302 || new_w->notebook.binding_type != old->notebook.binding_type
1303 || new_w->notebook.binding_width != old->notebook.binding_width
1304 || new_w->notebook.first_page_number != old->notebook.first_page_number
1305 || new_w->notebook.last_page_number != old->notebook.last_page_number
1306 || new_w->notebook.margin_width != old->notebook.margin_width
1307 || new_w->notebook.margin_height != old->notebook.margin_height
1308 || new_w->notebook.major_spacing != old->notebook.major_spacing
1309 || new_w->notebook.minor_spacing != old->notebook.minor_spacing
1310 || new_w->notebook.shadow_thickness != old->notebook.shadow_thickness))
1311 {
1312 relayout = True;
1313 redraw = True;
1314 }
1315
1316 /* if visual is changed, redraw */
1317 if (new_w->notebook.frame_background != old->notebook.frame_background
1318 || new_w->notebook.binding_pixmap != old->notebook.binding_pixmap
1319 || new_w->notebook.back_page_foreground !=
1320 old->notebook.back_page_foreground
1321 || new_w->notebook.back_page_background !=
1322 old->notebook.back_page_background)
1323 {
1324 redraw = True;
1325 }
1326
1327
1328 if (updateVisual)
1329 SetVisualConfig(new_w);
1330
1331 if (updateJoin)
1332 UpdateJoinSideChildren (new_w, (Dimension) 0);
1333
1334 if (relayout)
1335 {
1336 Dimension save_width, save_height;
1337 XtWidgetGeometry preferred_geo;
1338
1339 /* Store new w/h, restore old w/h, and adjust geometry to the old */
1340 save_width = XtWidth(new_w);
1341 save_height = XtHeight(new_w);
1342 XtWidth(new_w) = XtWidth(old);
1343 XtHeight(new_w) = XtHeight(old);
1344
1345 /* Adjust notebook's children type sizes to old size */
1346 AdjustGeometry(new_w, NULL, NULL);
1347
1348 /* Layout Children based on old notebook sizes */
1349 LayoutChildren(new_w, NULL);
1350
1351 /* Get preferred size unless app changed both width & height */
1352 if ((XtWidth(old) == save_width) || (XtHeight(old) == save_height))
1353 NewPreferredGeometry(new_w, NULL, NULL, &preferred_geo);
1354
1355 /* App request for width takes precedence over NewPreferredGeometry */
1356 if (XtWidth(old) != save_width)
1357 XtWidth(new_w) = save_width;
1358 else
1359 XtWidth(new_w) = preferred_geo.width;
1360
1361 /* App request for height takes precedence over NewPreferredGeometry */
1362 if (XtHeight(old) != save_height)
1363 XtHeight(new_w) = save_height;
1364 else
1365 XtHeight(new_w) = preferred_geo.height;
1366 }
1367
1368 if (visualFlag)
1369 redraw |= _XmNotifyChildrenVisual (ow, nw, visualFlag);
1370
1371
1372 return(redraw);
1373 }
1374
1375
1376 /*- QueryGeometry -----------------------------------------------------------
1377
1378 Method for the composite widget's QueryGeometry
1379
1380 Returns:
1381 preferred size if realized, else user/application w/h values
1382
1383 -----------------------------------------------------------------------------*/
1384 static XtGeometryResult
QueryGeometry(Widget w,XtWidgetGeometry * intended,XtWidgetGeometry * desired)1385 QueryGeometry (
1386 Widget w,
1387 XtWidgetGeometry *intended,
1388 XtWidgetGeometry *desired)
1389 {
1390
1391 /* Get the preferred w/h based on children preferred sizes */
1392 NewPreferredGeometry((XmNotebookWidget)w, NULL, NULL, desired);
1393
1394 /* Handle user initial size setting */
1395 if (!XtIsRealized(w))
1396 {
1397 if (XtWidth(w))
1398 desired->width = XtWidth(w);
1399 if (XtHeight(w))
1400 desired->height = XtHeight(w);
1401 }
1402
1403 /* Return result, XmeReplyToQueryGeometry will set CWidth and CHeight */
1404 return(XmeReplyToQueryGeometry(w, intended, desired));
1405 }
1406
1407
1408
1409 /*****************************************************************************
1410 * *
1411 * Composite Class Methods *
1412 * *
1413 *****************************************************************************/
1414
1415
1416 /*- GeometryManager ---------------------------------------------------------
1417
1418 Method for the composite widget's GeometryManager
1419
1420 -----------------------------------------------------------------------------*/
1421
1422 /*ARGSUSED*/
1423 static XtGeometryResult
GeometryManager(Widget instigator,XtWidgetGeometry * desired,XtWidgetGeometry * reply)1424 GeometryManager (
1425 Widget instigator,
1426 XtWidgetGeometry *desired,
1427 XtWidgetGeometry *reply) /* unused */
1428 {
1429 XmNotebookWidget nb = (XmNotebookWidget)XtParent(instigator);
1430 XmNotebookConstraint nc = NotebookConstraint(instigator);
1431 XtGeometryResult result = XtGeometryNo;
1432 XtWidgetGeometry myrequest, myallowed;
1433
1434 /* handle changes during ConstraintSetValues layout */
1435 if ( (nb->notebook.constraint_child == instigator)
1436 && ((IsX(desired)) && (IsY(desired))))
1437 {
1438 nb->notebook.constraint_child = NULL;
1439 XtX(instigator) = desired->x;
1440 XtY(instigator) = desired->y;
1441 if (IsWidth(desired))
1442 XtWidth(instigator) = desired->width;
1443 if (IsHeight(desired))
1444 XtHeight(instigator) = desired->height;
1445 return XtGeometryYes;
1446 }
1447
1448 /* only for resizing request */
1449 if ((nc->resizable || NB_IS_CHILD_TAB(nc->child_type))
1450 && (desired->request_mode & (CWWidth|CWHeight|CWBorderWidth))
1451 && !nb->notebook.in_setshadow)
1452 {
1453 /* Determine preferred geometry based on instigator preferrences */
1454 NewPreferredGeometry(nb, instigator, desired, &myrequest);
1455
1456 /*
1457 * Prepare resize request (as needed) to the parent
1458 */
1459 myrequest.request_mode = 0;
1460 if (IsQueryOnly(desired))
1461 myrequest.request_mode |= XtCWQueryOnly;
1462 if (IsWidth(desired) && XtWidth(nb) != myrequest.width)
1463 myrequest.request_mode |= CWWidth;
1464 if (IsHeight(desired) && XtHeight(nb) != myrequest.height)
1465 myrequest.request_mode |= CWHeight;
1466 if (IsBorder(desired) && XtBorderWidth(nb) != myrequest.border_width)
1467 myrequest.border_width |= CWBorderWidth;
1468
1469 /* ask parent, only if notebook resize request is needed */
1470 if (myrequest.request_mode)
1471 {
1472 if (NB_IS_CHILD_TAB(nc->child_type))
1473 result = XtGeometryYes;
1474 else /* nc->resizable */
1475 {
1476 result = XtMakeGeometryRequest((Widget)nb, &myrequest, &myallowed);
1477
1478 /* Parent unable to completely fulfill request */
1479 if (result == XtGeometryAlmost)
1480 result = XtGeometryNo;
1481 }
1482 }
1483
1484 /* Update the geometry, if necessary */
1485 if (result == XtGeometryYes && !IsQueryOnly(desired))
1486 {
1487 /* Adjust notebook's children type sizes to new size */
1488 AdjustGeometry(nb, instigator, desired);
1489
1490 /* Layout Children based on new notebook size */
1491 LayoutChildren(nb, instigator);
1492
1493 if (XtIsRealized((Widget)nb))
1494 XClearArea(XtDisplay((Widget)nb),XtWindow((Widget)nb),
1495 0,0,0,0,True);
1496 }
1497 }
1498 return result;
1499 }
1500
1501
1502 /*- ChangeManaged -----------------------------------------------------------
1503
1504 Method for the composite widget's ChangeManaged
1505
1506 Something changed in the set of managed children, so place
1507 the children and change the form widget size to reflect new size,
1508 if possible.
1509
1510 -----------------------------------------------------------------------------*/
1511 static void
ChangeManaged(Widget w)1512 ChangeManaged (
1513 Widget w)
1514 {
1515 XmNotebookWidget nb = (XmNotebookWidget)w;
1516 XtWidgetGeometry preferred;
1517
1518 /* ChangeManaged recursively called by SetPageScroller; return */
1519 if (nb->notebook.scroller_status == DEFAULT_CREATE)
1520 return;
1521
1522 /* if this is the first time through, set the page scroller */
1523 if (nb->notebook.scroller_status == DEFAULT_NONE)
1524 {
1525 SetPageScroller(nb);
1526 UpdateNavigators(nb);
1527 }
1528
1529 /* assign default page number to those who don't have */
1530 AssignDefaultPageNumber(nb);
1531
1532 /* invoke XmNpageChangedCallback for initial setting of current page */
1533 if (nb->notebook.first_change_managed
1534 && XtHasCallbacks(w, XmNpageChangedCallback) == XtCallbackHasSome)
1535 {
1536 XmNotebookCallbackStruct cbs;
1537
1538 cbs.reason = XmCR_NONE;
1539 cbs.event = NULL;
1540 cbs.page_number = nb->notebook.current_page_number;
1541 cbs.page_widget = GetChildWidget(nb,
1542 nb->notebook.current_page_number, XmPAGE);
1543 cbs.prev_page_number = XmUNSPECIFIED_PAGE_NUMBER;
1544 cbs.prev_page_widget = NULL;
1545
1546 /* Mark that the callback is being called and when it finishes */
1547 nb->notebook.in_callback = True;
1548 XtCallCallbackList(w, nb->notebook.page_change_callback, &cbs);
1549 nb->notebook.in_callback = False;
1550 }
1551
1552 /* sort children by their page number and update their activity */
1553 SortChildren(nb);
1554
1555 /*
1556 * Determine preferred notebook size based on new managed child
1557 */
1558
1559 /* Check if current size is the preferred size */
1560 if (NewPreferredGeometry(nb, NULL, NULL, &preferred))
1561 {
1562 /* Prepare parent geometry request */
1563 preferred.request_mode = 0;
1564 if (XtIsRealized((Widget)nb) || XtWidth(nb) == 0)
1565 preferred.request_mode |= CWWidth;
1566 if (XtIsRealized((Widget)nb) || XtHeight(nb) == 0)
1567 preferred.request_mode |= CWHeight;
1568
1569 /* Make parent geometry request, if necessary */
1570 if (preferred.request_mode)
1571 _XmMakeGeometryRequest((Widget)nb, &preferred);
1572
1573 /* Clear notebook area otherwise binder and backpage don't update. */
1574 if (XtIsRealized((Widget)nb) && !nb->notebook.first_change_managed)
1575 XClearArea(XtDisplay(nb), XtWindow(nb), 0, 0, 0, 0, True);
1576 }
1577
1578 /* Adjust notebook's children type sizes (based on notebook size) */
1579 AdjustGeometry(nb, NULL, NULL);
1580
1581 /* Layout Children (based on notebook size) */
1582 LayoutChildren(nb, NULL);
1583
1584 XmeNavigChangeManaged(w);
1585 nb->notebook.first_change_managed = False;
1586 }
1587
1588
1589 /*- InsertChild -------------------------------------------------------------
1590
1591 Method for the composite widget's InsertChild
1592
1593 -----------------------------------------------------------------------------*/
1594 static void
InsertChild(Widget child)1595 InsertChild (
1596 Widget child)
1597 {
1598 XmNotebookWidget nb = (XmNotebookWidget)XtParent(child);
1599 XmNotebookConstraint nc = NotebookConstraint(child);
1600 XmScrollFrameTrait scroll_frameT;
1601 XtWidgetProc insert_child;
1602
1603 /* check if trying to insert an invalid object */
1604 if (!XtIsRectObj(child))
1605 return;
1606
1607 /* call manager's InsertChild method */
1608 _XmProcessLock();
1609 insert_child = ((XmManagerWidgetClass)xmManagerWidgetClass)
1610 ->composite_class.insert_child;
1611 _XmProcessUnlock();
1612 (*insert_child)(child);
1613
1614 /* add some keyboard traversal stuff */
1615 switch (nc->child_type)
1616 {
1617 case XmPAGE_SCROLLER:
1618 /* First: take care of previous page scroller */
1619
1620 /* default page scroller not yet made, so just put this one in */
1621 if (nb->notebook.scroller_status == DEFAULT_NONE)
1622 nb->notebook.scroller_status = DEFAULT_GONE;
1623
1624 /* remove previously created default page scroller */
1625 else if (nb->notebook.scroller_status == DEFAULT_USED)
1626 {
1627 nb->notebook.scroller_status = DEFAULT_CREATE;
1628
1629 /* remove navigator, if page scroller is a navigator */
1630 if (NB_IS_CHILD_NAVIGATOR(nb->notebook.scroller))
1631 {
1632 if ((scroll_frameT=NB_SCROLL_FRAME(nb)) != NULL
1633 && scroll_frameT->removeNavigator != NULL)
1634 scroll_frameT->removeNavigator((Widget) nb,
1635 nb->notebook.scroller);
1636 }
1637 XtDestroyWidget(nb->notebook.scroller);
1638
1639 nb->notebook.scroller_status = DEFAULT_GONE;
1640 }
1641
1642 /* remove previously created non-default page scroller */
1643 else if (nb->notebook.scroller_status == DEFAULT_GONE
1644 && nb->notebook.scroller != NULL)
1645 {
1646 nb->notebook.scroller_status = DEFAULT_CREATE;
1647
1648 /* remove navigator, if page scroller is a navigator */
1649 if (NB_IS_CHILD_NAVIGATOR(nb->notebook.scroller))
1650 {
1651 if ((scroll_frameT=NB_SCROLL_FRAME(nb)) != NULL
1652 && scroll_frameT->removeNavigator != NULL)
1653 scroll_frameT->removeNavigator((Widget)nb,
1654 nb->notebook.scroller);
1655 }
1656 XtUnmanageChild(nb->notebook.scroller);
1657
1658 nb->notebook.scroller_status = DEFAULT_GONE;
1659 }
1660
1661 /* Second: take care of this new page scroller */
1662
1663 /* update scroller's translation table */
1664 nb->notebook.scroller = child;
1665
1666 /* add navigator, if page scroller has navigator trait */
1667 if (NB_IS_CHILD_NAVIGATOR(nb->notebook.scroller))
1668 {
1669 if ((scroll_frameT = NB_SCROLL_FRAME(nb)) != NULL
1670 && scroll_frameT->addNavigator != NULL)
1671 scroll_frameT->addNavigator((Widget)nb,
1672 child, NavigDimensionX);
1673 }
1674
1675 /* update navigators so this one get initial info */
1676 UpdateNavigators(nb);
1677
1678 break;
1679
1680 case XmPAGE:
1681 case XmSTATUS_AREA:
1682 XtVaSetValues(child, XmNnavigationType, XmTAB_GROUP, NULL);
1683 break;
1684
1685 case XmMAJOR_TAB:
1686 case XmMINOR_TAB:
1687 /* Install activiation callback */
1688 {
1689 XmActivatableTrait activeT;
1690
1691 if ((activeT=NB_ACTIVATABLE(child)) != NULL
1692 && activeT->changeCB != NULL)
1693 activeT->changeCB(child, TabPressed,
1694 (XtPointer)(unsigned long)(NB_IS_CHILD_MAJOR(nc->child_type)
1695 ? XmCR_MAJOR_TAB : XmCR_MINOR_TAB), True);
1696 }
1697
1698 /* Update JoinSide information */
1699 (void) UpdateJoinSide(nb, child, nc->child_type, (Dimension) 0);
1700
1701 /* Install accelerators */
1702 if (!XmIsGadget(child))
1703 XtInstallAccelerators(child, (Widget)nb);
1704 break;
1705 }
1706 }
1707
1708
1709 /*- DeleteChild -------------------------------------------------------------
1710
1711 Method for the composite widget's DeleteChild
1712
1713 -----------------------------------------------------------------------------*/
1714 static void
DeleteChild(Widget child)1715 DeleteChild (
1716 Widget child)
1717 {
1718 XmNotebookWidget nb = (XmNotebookWidget)XtParent(child);
1719 XmNotebookConstraint nc = NotebookConstraint(child);
1720 XmScrollFrameTrait scroll_frameT;
1721 XtWidgetProc delete_child;
1722
1723 /* clear child pointers in Notebook */
1724 switch (nc->child_type)
1725 {
1726 case XmPAGE_SCROLLER:
1727 if (nb->notebook.scroller == child)
1728 {
1729 /* remove navigator */
1730 if (NB_IS_CHILD_NAVIGATOR(nb->notebook.scroller))
1731 {
1732 if ((scroll_frameT=NB_SCROLL_FRAME(nb)) != NULL
1733 && scroll_frameT->removeNavigator != NULL)
1734 scroll_frameT->removeNavigator((Widget)nb,
1735 nb->notebook.scroller);
1736 }
1737 /* Mark that no page scroller is established */
1738 nb->notebook.scroller = NULL;
1739 nb->notebook.scroller_status = DEFAULT_GONE;
1740 }
1741 break;
1742 case XmMAJOR_TAB_SCROLLER:
1743 nb->notebook.next_major = NULL;
1744 nb->notebook.prev_major = NULL;
1745 break;
1746 case XmMINOR_TAB_SCROLLER:
1747 nb->notebook.next_minor = NULL;
1748 nb->notebook.prev_minor = NULL;
1749 break;
1750 }
1751
1752 /* call manager's DeleteChild method */
1753 _XmProcessLock();
1754 delete_child = ((XmManagerWidgetClass)xmManagerWidgetClass)
1755 ->composite_class.delete_child;
1756 _XmProcessUnlock();
1757 (*delete_child)(child);
1758 }
1759
1760
1761
1762 /*****************************************************************************
1763 * *
1764 * Constraint Class Methods *
1765 * *
1766 *****************************************************************************/
1767
1768
1769 /*- ConstraintInitialize ----------------------------------------------------
1770
1771 Initialize method for Notebook's constraint class
1772
1773 A default page number will be provided when the widget is managed.
1774
1775 -----------------------------------------------------------------------------*/
1776
1777 /*ARGSUSED*/
1778 static void
ConstraintInitialize(Widget req,Widget new_w,ArgList args,Cardinal * num)1779 ConstraintInitialize (
1780 Widget req, /* unused */
1781 Widget new_w,
1782 ArgList args, /* unused */
1783 Cardinal *num) /* unused */
1784 {
1785 XmNotebookConstraint nc = NotebookConstraint(new_w);
1786
1787 /* check for invalid object */
1788 if (!XtIsRectObj(new_w))
1789 return;
1790
1791 /* validate the child type */
1792 if (nc->child_type != XmMAJOR_TAB_SCROLLER
1793 && nc->child_type != XmMINOR_TAB_SCROLLER
1794 && !XmRepTypeValidValue(XmRID_NB_CHILD_TYPE, nc->child_type, new_w))
1795 nc->child_type = XmNONE;
1796
1797 /* convert to internal */
1798 if (nc->child_type == XmNONE)
1799 {
1800 if (NB_IS_CHILD_ACTIVATABLE(new_w))
1801 nc->child_type = XmMAJOR_TAB;
1802 else if (NB_IS_CHILD_ACCESSTEXTUAL(new_w))
1803 nc->child_type = XmSTATUS_AREA;
1804 else if (NB_IS_CHILD_NAVIGATOR(new_w))
1805 nc->child_type = XmPAGE_SCROLLER;
1806 else
1807 nc->child_type = XmPAGE;
1808 }
1809 }
1810
1811
1812 /*- ConstraintSetValues -----------------------------------------------------
1813
1814 SetValue method for notebook's constraint class
1815
1816 -----------------------------------------------------------------------------*/
1817
1818 /*ARGSUSED*/
1819 static Boolean
ConstraintSetValues(Widget old_w,Widget req,Widget new_w,ArgList args,Cardinal * num)1820 ConstraintSetValues (
1821 Widget old_w,
1822 Widget req, /* unused */
1823 Widget new_w,
1824 ArgList args, /* unused */
1825 Cardinal *num) /* unused */
1826 {
1827 XmNotebookWidget nb = (XmNotebookWidget)XtParent(new_w);
1828 XmNotebookConstraint old_nc = NotebookConstraint(old_w);
1829 XmNotebookConstraint new_nc = NotebookConstraint(new_w);
1830 Boolean redraw = False;
1831 Boolean need_reset = False;
1832
1833 /* check for invalid object */
1834 if (!XtIsRectObj(new_w))
1835 return False;
1836
1837 /* XmNnotebookChildType is only CG, not Settable */
1838 if (new_nc->child_type != old_nc->child_type) {
1839 new_nc->child_type = old_nc->child_type;
1840 XmeWarning(new_w, MESSAGE0);
1841 }
1842
1843 /* if the page number is changed, sort again */
1844 /* by just repositioning that child */
1845 if (new_nc->page_number != old_nc->page_number)
1846 {
1847 /* check for last page number change */
1848 if (nb->notebook.dynamic_last_page_num)
1849 {
1850 if (new_nc->page_number > nb->notebook.last_page_number
1851 && XtIsManaged(new_w)
1852 && (NB_IS_CHILD_PAGE(new_nc->child_type)
1853 || NB_IS_CHILD_TAB(new_nc->child_type)
1854 || NB_IS_CHILD_STATUS(new_nc->child_type)))
1855 need_reset = SetLastPageNumber(nb, new_nc->page_number);
1856 else if (old_nc->page_number == nb->notebook.last_page_number)
1857 need_reset = AssignDefaultPageNumber(nb);
1858 }
1859
1860 /* re-sort and check child list */
1861 RepositionChild(nb, new_w);
1862 SetActiveChildren(nb);
1863
1864 /* check for changes that affect layout */
1865 if (!nb->notebook.in_callback)
1866 {
1867 switch(new_nc->child_type)
1868 {
1869 case XmPAGE:
1870 case XmSTATUS_AREA:
1871 if (nb->notebook.current_page_number == old_nc->page_number
1872 || nb->notebook.current_page_number == new_nc->page_number)
1873 {
1874 if (need_reset)
1875 ResetTopPointers(nb, XmNONE, 0);
1876 nb->notebook.constraint_child = new_w;
1877 LayoutPages(nb, NULL);
1878 redraw = True;
1879 }
1880 break;
1881 case XmMAJOR_TAB:
1882 ResetTopPointers(nb, XmNONE, 0);
1883 nb->notebook.constraint_child = new_w;
1884 LayoutMajorTabs(nb, NULL);
1885 LayoutMinorTabs(nb, NULL);
1886 redraw = True;
1887 break;
1888 case XmMINOR_TAB:
1889 ResetTopPointers(nb, XmNONE, 0);
1890 nb->notebook.constraint_child = new_w;
1891 LayoutMinorTabs(nb, NULL);
1892 redraw = True;
1893 break;
1894 } /* switch */
1895 } /* if */
1896 } /* if */
1897
1898 return(redraw);
1899 }
1900
1901
1902
1903 /*****************************************************************************
1904 * *
1905 * Initializing & Resource Managing *
1906 * *
1907 *****************************************************************************/
1908
1909
1910 /*- GetDefaultBackPagePos ---------------------------------------------------
1911
1912 Get the default back page position
1913
1914 -----------------------------------------------------------------------------*/
1915
1916 /*ARGSUSED*/
1917 static void
GetDefaultFrameBackground(Widget w,int offset,XrmValue * value)1918 GetDefaultFrameBackground(
1919 Widget w,
1920 int offset, /* unused */
1921 XrmValue *value)
1922 {
1923 value->addr = (XtPointer) &w->core.background_pixel;
1924 }
1925
1926
1927 /*ARGSUSED*/
1928 static void
GetDefaultBackPageBackground(Widget w,int offset,XrmValue * value)1929 GetDefaultBackPageBackground(
1930 Widget w,
1931 int offset, /* unused */
1932 XrmValue *value)
1933 {
1934 XmNotebookWidget nb = (XmNotebookWidget)w;
1935 static Pixel pixel;
1936
1937 value->addr = (XtPointer) &pixel;
1938
1939 XmGetColors(XtScreen(w), nb->core.colormap, nb->notebook.frame_background,
1940 NULL, NULL, NULL, &pixel);
1941 }
1942
1943
1944 /*ARGSUSED*/
1945 static void
GetDefaultBackPagePos(Widget w,int offset,XrmValue * value)1946 GetDefaultBackPagePos (
1947 Widget w,
1948 int offset, /* unused */
1949 XrmValue *value)
1950 {
1951 static unsigned char back_page_pos;
1952 XmNotebookWidget nb = (XmNotebookWidget)w;
1953
1954 /* initialize the notebook layout default */
1955 if (LayoutIsRtoLM(w))
1956 {
1957 if (nb->notebook.orientation == XmVERTICAL)
1958 /* RIGHT_TO_LEFT and VERTICAL */
1959 back_page_pos = XmBOTTOM_LEFT;
1960 else
1961 /* RIGHT_TO_LEFT and HORIZONTAL */
1962 back_page_pos = XmBOTTOM_LEFT;
1963 }
1964 else
1965 {
1966 if (nb->notebook.orientation == XmVERTICAL)
1967 /* LEFT_TO_RIGHT and VERTICAL */
1968 back_page_pos = XmBOTTOM_RIGHT;
1969 else
1970 /* LEFT_TO_RIGHT and HORIZONTAL */
1971 back_page_pos = XmBOTTOM_RIGHT;
1972 }
1973 /*
1974 * This will have to change when BOTTOM_TO_TOP is supported for
1975 * XmNlayoutDirection.
1976 */
1977
1978 value->addr = (XPointer) &back_page_pos;
1979 }
1980
1981 /* Same logic as the GetDefaultBackPagePos default proc ... rewritten
1982 * without the static variable - for use from the Initialize proc .
1983 */
1984 static unsigned char
GetDefaultBackPagePosAgain(Widget w)1985 GetDefaultBackPagePosAgain (
1986 Widget w)
1987 {
1988 unsigned char back_page_pos;
1989 XmNotebookWidget nb = (XmNotebookWidget)w;
1990
1991 if (LayoutIsRtoLM(w))
1992 {
1993 if (nb->notebook.orientation == XmVERTICAL)
1994 /* RIGHT_TO_LEFT and VERTICAL */
1995 back_page_pos = XmBOTTOM_LEFT;
1996 else
1997 /* RIGHT_TO_LEFT and HORIZONTAL */
1998 back_page_pos = XmBOTTOM_LEFT;
1999 }
2000 else
2001 {
2002 if (nb->notebook.orientation == XmVERTICAL)
2003 /* LEFT_TO_RIGHT and VERTICAL */
2004 back_page_pos = XmBOTTOM_RIGHT;
2005 else
2006 /* LEFT_TO_RIGHT and HORIZONTAL */
2007 back_page_pos = XmBOTTOM_RIGHT;
2008 }
2009
2010 return back_page_pos;
2011 }
2012
2013 /*- FromOrientationPixels ---------------------------------------------------
2014
2015 Determines orientation and calls appropriate converter.
2016
2017 -----------------------------------------------------------------------------*/
2018 static void
FromOrientationPixels(Widget w,int offset,XtArgVal * value)2019 FromOrientationPixels (
2020 Widget w,
2021 int offset,
2022 XtArgVal *value)
2023 {
2024 XmNotebookWidget nb = (XmNotebookWidget)w;
2025
2026 if ((int)(*value) < 0)
2027 *value = 0;
2028 if (nb->notebook.orientation == XmHORIZONTAL)
2029 XmeFromHorizontalPixels(w, offset, value);
2030 else
2031 XmeFromVerticalPixels(w, offset, value);
2032 }
2033
2034
2035 /*- ToOrientationPixels ----------------------------------------------------
2036
2037 Determines orientation and calls appropriate converter.
2038
2039 -----------------------------------------------------------------------------*/
2040 static XmImportOperator
ToOrientationPixels(Widget w,int offset,XtArgVal * value)2041 ToOrientationPixels (
2042 Widget w,
2043 int offset,
2044 XtArgVal *value)
2045 {
2046 XmNotebookWidget nb = (XmNotebookWidget)w;
2047
2048 if (nb->notebook.orientation == XmHORIZONTAL)
2049 return(XmeToHorizontalPixels(w, offset, value));
2050 else
2051 return(XmeToVerticalPixels(w, offset, value));
2052 }
2053
2054
2055 /*- FromOrientationOppositePixels -------------------------------------------
2056
2057 Determines orientation and calls appropriate converter.
2058
2059 -----------------------------------------------------------------------------*/
2060 static void
FromOrientationOppositePixels(Widget w,int offset,XtArgVal * value)2061 FromOrientationOppositePixels (
2062 Widget w,
2063 int offset,
2064 XtArgVal *value)
2065 {
2066 XmNotebookWidget nb = (XmNotebookWidget)w;
2067
2068 if ((int)(*value) < 0)
2069 *value = 0;
2070 if (nb->notebook.orientation == XmHORIZONTAL)
2071 XmeFromVerticalPixels(w, offset, value);
2072 else
2073 XmeFromHorizontalPixels(w, offset, value);
2074 }
2075
2076
2077 /*- ToOrientationOppositePixels --------------------------------------------
2078
2079 Determines orientation and calls appropriate converter.
2080
2081 -----------------------------------------------------------------------------*/
2082 static XmImportOperator
ToOrientationOppositePixels(Widget w,int offset,XtArgVal * value)2083 ToOrientationOppositePixels (
2084 Widget w,
2085 int offset,
2086 XtArgVal *value)
2087 {
2088 XmNotebookWidget nb = (XmNotebookWidget)w;
2089
2090 if (nb->notebook.orientation == XmHORIZONTAL)
2091 return(XmeToVerticalPixels(w, offset, value));
2092 else
2093 return(XmeToHorizontalPixels(w, offset, value));
2094 }
2095
2096
2097 /*- CreateTabScrollers -----------------------------------------------------
2098
2099 Create Notebook's tab scrollers
2100
2101 -----------------------------------------------------------------------------*/
2102 static void
CreateTabScrollers(XmNotebookWidget nb)2103 CreateTabScrollers (
2104 XmNotebookWidget nb)
2105 {
2106 /* creating major tab scrollers */
2107 nb->notebook.next_major = XtVaCreateManagedWidget(MAJOR_TAB_NEXT_NAME,
2108 xmArrowButtonGadgetClass, (Widget)nb,
2109 XmNwidth, TAB_SCROLLER_WIDTH_DEFAULT,
2110 XmNheight, TAB_SCROLLER_HEIGHT_DEFAULT,
2111 XmNnotebookChildType, XmMAJOR_TAB_SCROLLER,
2112 XmNtraversalOn, False,
2113 NULL);
2114 ((XmActivatableTrait)XmeTraitGet((XtPointer)
2115 XtClass((Widget)nb->notebook.next_major),XmQTactivatable))->
2116 changeCB(nb->notebook.next_major,FlipTabs,NULL,True);
2117
2118 nb->notebook.prev_major = XtVaCreateManagedWidget(MAJOR_TAB_PREV_NAME,
2119 xmArrowButtonGadgetClass, (Widget)nb,
2120 XmNwidth, TAB_SCROLLER_WIDTH_DEFAULT,
2121 XmNheight, TAB_SCROLLER_HEIGHT_DEFAULT,
2122 XmNnotebookChildType, XmMAJOR_TAB_SCROLLER,
2123 XmNtraversalOn, False,
2124 NULL);
2125 ((XmActivatableTrait)XmeTraitGet((XtPointer)
2126 XtClass((Widget)nb->notebook.prev_major),XmQTactivatable))->
2127 changeCB(nb->notebook.prev_major,FlipTabs,NULL,True);
2128
2129 /* creating minor tab scrollers */
2130 nb->notebook.next_minor = XtVaCreateManagedWidget(MINOR_TAB_NEXT_NAME,
2131 xmArrowButtonGadgetClass, (Widget)nb,
2132 XmNwidth, TAB_SCROLLER_WIDTH_DEFAULT,
2133 XmNheight, TAB_SCROLLER_HEIGHT_DEFAULT,
2134 XmNnotebookChildType, XmMINOR_TAB_SCROLLER,
2135 XmNtraversalOn, False,
2136 NULL);
2137 ((XmActivatableTrait)XmeTraitGet((XtPointer)
2138 XtClass((Widget)nb->notebook.next_minor),XmQTactivatable))->
2139 changeCB(nb->notebook.next_minor,FlipTabs,NULL,True);
2140
2141 nb->notebook.prev_minor = XtVaCreateManagedWidget(MINOR_TAB_PREV_NAME,
2142 xmArrowButtonGadgetClass, (Widget)nb,
2143 XmNwidth, TAB_SCROLLER_WIDTH_DEFAULT,
2144 XmNheight, TAB_SCROLLER_HEIGHT_DEFAULT,
2145 XmNnotebookChildType, XmMINOR_TAB_SCROLLER,
2146 XmNtraversalOn, False,
2147 NULL);
2148 ((XmActivatableTrait)XmeTraitGet((XtPointer)
2149 XtClass((Widget)nb->notebook.prev_minor),XmQTactivatable))->
2150 changeCB(nb->notebook.prev_minor,FlipTabs,NULL,True);
2151 }
2152
2153
2154 /*- SetVisualConfig ---------------------------------------------------------
2155
2156 Sets Notebook visual configuration private variables.
2157
2158 -----------------------------------------------------------------------------*/
2159 static void
SetVisualConfig(XmNotebookWidget nb)2160 SetVisualConfig (
2161 XmNotebookWidget nb)
2162 {
2163 /* set tab and binding position variables */
2164 if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT &&
2165 nb->notebook.orientation == XmHORIZONTAL)
2166 {
2167 nb->notebook.major_pos = RIGHT;
2168 nb->notebook.minor_pos = BOTTOM;
2169 nb->notebook.binding_pos = LEFT;
2170 }
2171 else if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT &&
2172 nb->notebook.orientation == XmVERTICAL)
2173 {
2174 nb->notebook.major_pos = BOTTOM;
2175 nb->notebook.minor_pos = RIGHT;
2176 nb->notebook.binding_pos = TOP;
2177 }
2178 else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT &&
2179 nb->notebook.orientation == XmHORIZONTAL)
2180 {
2181 nb->notebook.major_pos = LEFT;
2182 nb->notebook.minor_pos = BOTTOM;
2183 nb->notebook.binding_pos = RIGHT;
2184 }
2185 else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT &&
2186 nb->notebook.orientation == XmVERTICAL)
2187 {
2188 nb->notebook.major_pos = BOTTOM;
2189 nb->notebook.minor_pos = LEFT;
2190 nb->notebook.binding_pos = TOP;
2191 }
2192 else if (nb->notebook.back_page_pos == XmTOP_RIGHT &&
2193 nb->notebook.orientation == XmHORIZONTAL)
2194 {
2195 nb->notebook.major_pos = RIGHT;
2196 nb->notebook.minor_pos = TOP;
2197 nb->notebook.binding_pos = LEFT;
2198 }
2199 else if (nb->notebook.back_page_pos == XmTOP_RIGHT &&
2200 nb->notebook.orientation == XmVERTICAL)
2201 {
2202 nb->notebook.major_pos = TOP;
2203 nb->notebook.minor_pos = RIGHT;
2204 nb->notebook.binding_pos = BOTTOM;
2205 }
2206 else if (nb->notebook.back_page_pos == XmTOP_LEFT &&
2207 nb->notebook.orientation == XmHORIZONTAL)
2208 {
2209 nb->notebook.major_pos = LEFT;
2210 nb->notebook.minor_pos = TOP;
2211 nb->notebook.binding_pos = RIGHT;
2212 }
2213 else if (nb->notebook.back_page_pos == XmTOP_LEFT &&
2214 nb->notebook.orientation == XmVERTICAL)
2215 {
2216 nb->notebook.major_pos = TOP;
2217 nb->notebook.minor_pos = LEFT;
2218 nb->notebook.binding_pos = BOTTOM;
2219 }
2220 }
2221
2222
2223 /*- UpdateJoinSide ------------------------------------------------------------
2224
2225 Update tab's JoinSide Trait to match current visual configuration.
2226
2227 Uses instance state:
2228 major_pos
2229 minor_pos
2230 Returns
2231 True, if the child is major or minor tab and holds the
2232 JoinSide trait. Otherwise, returns False.
2233
2234 -----------------------------------------------------------------------------*/
2235 static Boolean
UpdateJoinSide(XmNotebookWidget nb,Widget child,unsigned char child_type,Dimension shadow_thickness)2236 UpdateJoinSide (
2237 XmNotebookWidget nb,
2238 Widget child,
2239 unsigned char child_type,
2240 Dimension shadow_thickness)
2241 {
2242 XmJoinSideTrait joinsideT; /* child JoinSide trait */
2243 unsigned char side_of_book; /* side of notebook tab is on */
2244 unsigned char side_to_join; /* side to join */
2245
2246 /* Determine side of nookbook tabs reside */
2247 if (NB_IS_CHILD_MAJOR(child_type))
2248 side_of_book = nb->notebook.major_pos;
2249 else if (NB_IS_CHILD_MINOR(child_type))
2250 side_of_book = nb->notebook.minor_pos;
2251 else
2252 return(False);
2253
2254 /* Update JoinSide trait infomation, unless trait not found */
2255 if ((joinsideT=NB_JOINSIDE(child)) != NULL
2256 && joinsideT->setValue != NULL)
2257 {
2258 /* Convert notebook position to JoinSide position */
2259 switch (side_of_book)
2260 {
2261 case RIGHT:
2262 side_to_join = XmLEFT;
2263 break;
2264 case BOTTOM:
2265 side_to_join = XmTOP;
2266 break;
2267 case LEFT:
2268 side_to_join = XmRIGHT;
2269 break;
2270 case TOP:
2271 default:
2272 side_to_join = XmBOTTOM;
2273 break;
2274 }
2275 /* Invoke JoinSideSetValues */
2276 joinsideT->setValue(child, side_to_join, shadow_thickness);
2277 return(True);
2278 }
2279
2280 return(False);
2281 }
2282
2283
2284 /*- UpdateJoinSideChildren --------------------------------------------------
2285
2286 Update JoinSide aware children of new shadow_thickness or JoinSide.
2287
2288 -----------------------------------------------------------------------------*/
2289 static void
UpdateJoinSideChildren(XmNotebookWidget nb,Dimension shadow_thickness)2290 UpdateJoinSideChildren (
2291 XmNotebookWidget nb,
2292 Dimension shadow_thickness)
2293 {
2294 Widget cw; /* child widget */
2295 unsigned char ct; /* child constraint type */
2296 int i;
2297
2298 for (i=0; i < nb->composite.num_children; i++)
2299 {
2300 cw = nb->composite.children[i];
2301 ct = NotebookConstraint(cw)->child_type;
2302 if (NB_IS_CHILD_TAB(ct))
2303 (void) UpdateJoinSide(nb, cw, ct, shadow_thickness);
2304 }
2305 }
2306
2307
2308 /*- SetPageScroller ---------------------------------------------------------
2309
2310 Set the visual configuration of the page scroller.
2311
2312 It creates the default page scroller if no page scroller
2313 is created yet (consisting of a SpinBox with TextField child).
2314
2315 -----------------------------------------------------------------------------*/
2316 static void
SetPageScroller(XmNotebookWidget nb)2317 SetPageScroller (
2318 XmNotebookWidget nb)
2319 {
2320
2321 /* Only create default page scroller if none currently exists */
2322 if (nb->notebook.scroller_status != DEFAULT_NONE)
2323 return;
2324
2325 /* Mark that we are in the process of creating the default */
2326 nb->notebook.scroller_status = DEFAULT_CREATE;
2327
2328 nb->notebook.scroller = XtVaCreateManagedWidget(PAGE_SCROLLER_NAME,
2329 xmSpinBoxWidgetClass, (Widget)nb,
2330 XmNarrowLayout, XmARROWS_SPLIT,
2331 XmNnotebookChildType, XmPAGE_SCROLLER,
2332 NULL);
2333
2334 nb->notebook.scroller_child = XtVaCreateManagedWidget(NB_TEXT_FIELD_NAME,
2335 xmTextFieldWidgetClass, nb->notebook.scroller,
2336 XmNspinBoxChildType, XmNUMERIC,
2337 XmNcolumns, 6,
2338 XmNmarginHeight, 2,
2339 XmNcursorPositionVisible, False,
2340 XmNeditable, False,
2341 XmNtraversalOn, True,
2342 NULL);
2343
2344 /* Mark that the default page scroller has been established */
2345 nb->notebook.scroller_status = DEFAULT_USED;
2346 }
2347
2348
2349
2350 /*****************************************************************************
2351 * *
2352 * Child Layout Functions *
2353 * *
2354 *****************************************************************************/
2355
2356
2357 /*- LayoutChildren ----------------------------------------------------------
2358
2359 Function to layout Notebook's children
2360
2361 -----------------------------------------------------------------------------*/
2362 static void
LayoutChildren(XmNotebookWidget nb,Widget instigator)2363 LayoutChildren (
2364 XmNotebookWidget nb,
2365 Widget instigator)
2366 {
2367 /* reset top pointers of tabs */
2368 ResetTopPointers(nb, XmNONE, 0);
2369
2370 /* layout children */
2371 LayoutPages(nb, instigator);
2372 LayoutMajorTabs(nb, instigator);
2373 LayoutMinorTabs(nb, instigator);
2374 }
2375
2376
2377 /*- LayoutPages -------------------------------------------------------------
2378
2379 Function to layout Page, Status, and Page Scroller.
2380
2381 Uses instance state:
2382 current_page_number,
2383 orientation, and
2384 precalculated sizes of each child type.
2385
2386 Called from:
2387 LayoutChildren(), when performing complete relayout
2388 ConstraintSetValues(), when child page number changes
2389 GotoPage(), when notebook.current_page_number changes
2390
2391 -----------------------------------------------------------------------------*/
2392 static void
LayoutPages(XmNotebookWidget nb,Widget instigator)2393 LayoutPages (
2394 XmNotebookWidget nb,
2395 Widget instigator)
2396 {
2397 XmNotebookConstraint nc;
2398 Widget child;
2399 int i;
2400 Dimension x, y, x1, y1, x2;
2401
2402 /* get the page's x, y position */
2403 x = nb->notebook.margin_width + nb->notebook.shadow_thickness + 1;
2404 y = nb->notebook.margin_height + nb->notebook.shadow_thickness + 1;
2405 if (nb->notebook.binding_pos == LEFT)
2406 x += nb->notebook.real_binding_width;
2407 else if (nb->notebook.binding_pos == TOP)
2408 y += nb->notebook.real_binding_width;
2409 if (nb->notebook.major_pos == LEFT)
2410 x += NB_MAJOR_MAX(nb, nb->notebook.major_width,
2411 nb->notebook.major_scroller_width) + nb->notebook.back_page_size;
2412 else if (nb->notebook.major_pos == TOP)
2413 y += NB_MAJOR_MAX(nb, nb->notebook.major_height,
2414 nb->notebook.major_scroller_height) + nb->notebook.back_page_size;
2415 if (nb->notebook.minor_pos == LEFT)
2416 x += NB_MINOR_MAX(nb, nb->notebook.minor_width,
2417 nb->notebook.minor_scroller_width) + nb->notebook.back_page_size;
2418 else if (nb->notebook.minor_pos == TOP)
2419 y += NB_MINOR_MAX(nb, nb->notebook.minor_height,
2420 nb->notebook.minor_scroller_height) + nb->notebook.back_page_size;
2421
2422 /* get the status area and the page scroller's position */
2423 y1 = y + nb->notebook.page_height + nb->notebook.margin_height;
2424 if (nb->notebook.back_page_pos == XmTOP_RIGHT ||
2425 nb->notebook.back_page_pos == XmBOTTOM_RIGHT)
2426 {
2427 x1 = x;
2428 x2 = x + nb->notebook.page_width - nb->notebook.scroller_width;
2429 }
2430 else
2431 {
2432 x1 = x + nb->notebook.page_width - nb->notebook.status_width;
2433 x2 = x;
2434 }
2435
2436 /* resize pages & status */
2437 for (i = 0; i < nb->composite.num_children; i++)
2438 {
2439 child = nb->composite.children[i];
2440 nc = NotebookConstraint(child);
2441 if ( NB_IS_CHILD_PAGE(nc->child_type)
2442 || NB_IS_CHILD_STATUS(nc->child_type) )
2443 {
2444 if (nc->active &&
2445 nc->page_number == nb->notebook.current_page_number)
2446 {
2447 if (NB_IS_CHILD_PAGE(nc->child_type))
2448 ShowChild(child, instigator, x, y,
2449 nb->notebook.page_width,
2450 nb->notebook.page_height);
2451 else if (NB_IS_CHILD_STATUS(nc->child_type))
2452 ShowChild(child, instigator, x1, y1,
2453 nb->notebook.status_width,
2454 nb->notebook.status_height);
2455 }
2456 else
2457 {
2458 /* This is to get HideChild to function properly on
2459 widgets such as Form which fail to properly set
2460 default width/height to a non-zero value */
2461 if (nb->notebook.first_change_managed
2462 && (!XtWidth(child) && !XtHeight(child)))
2463 {
2464 XtWidth(child) = 10;
2465 XtHeight(child) = 10;
2466 HideChild(child, instigator);
2467 XtWidth(child) = 0;
2468 XtHeight(child) = 0;
2469 }
2470 else
2471 HideChild(child, instigator);
2472 }
2473 }
2474 }
2475
2476 /* Show the page scroller */
2477 if (nb->notebook.scroller != NULL)
2478 {
2479 child = nb->notebook.scroller;
2480 ShowChild(child, instigator, x2, y1,
2481 nb->notebook.scroller_width,
2482 nb->notebook.scroller_height);
2483 }
2484 }
2485
2486
2487 /*- LayoutMajorTabs ---------------------------------------------------------
2488
2489 Function to layout major tabs
2490
2491 -----------------------------------------------------------------------------*/
2492 static void
LayoutMajorTabs(XmNotebookWidget nb,Widget instigator)2493 LayoutMajorTabs (
2494 XmNotebookWidget nb,
2495 Widget instigator)
2496 {
2497 XmNotebookConstraint nc; /* constraint pointer */
2498 Widget child; /* a major tab widget */
2499 Widget join_child = NULL; /* top major and joinSide tab */
2500 int x, y, tmpx, tmpy; /* tab's geometry */
2501 int tab_count; /* # of tabs shown */
2502 int margin_w, margin_h; /* temporary margin value */
2503 int sx1, sy1, sx2, sy2; /* tab scroller position */
2504 int fixed; /* back page fixed position */
2505 int limit; /* the last possible position */
2506 int delta, spacing; /* major tab spacing */
2507 int first_major, top_major; /* page# of first and top major tabs */
2508 unsigned char prev, next; /* for tab scroller arrow direction */
2509 Boolean gray_prev, gray_next; /* True if need to gray out scrollers */
2510 int i;
2511 unsigned char direction;
2512 int total_major_tabs, top_tab_count = 0, current_tab = 0;
2513 /*
2514 * Initialize
2515 */
2516 first_major = nb->notebook.first_major ?
2517 NotebookConstraint(nb->notebook.first_major)->page_number :
2518 nb->notebook.first_page_number - 1;
2519 top_major = nb->notebook.top_major ?
2520 NotebookConstraint(nb->notebook.top_major)->page_number :
2521 nb->notebook.first_page_number - 1;
2522 gray_prev = gray_next = True;
2523 sx1 = sy1 = sx2 = sy2 = 0;
2524
2525 /*
2526 * Determine tab margin spacing and tab staggering
2527 */
2528 spacing = MAX(nb->notebook.major_spacing, nb->notebook.shadow_thickness);
2529 delta = nb->notebook.back_page_size / nb->notebook.real_back_page_number;
2530
2531 /*
2532 * Determine tab positions
2533 */
2534 if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT &&
2535 nb->notebook.orientation == XmHORIZONTAL)
2536 {
2537 /* set starting position */
2538 x = nb->notebook.real_binding_width + nb->notebook.frame_width;
2539 y = nb->notebook.back_page_size;
2540 fixed = x + nb->notebook.back_page_size;
2541 limit = nb->notebook.frame_height -
2542 nb->notebook.major_height -
2543 nb->notebook.shadow_thickness;
2544 if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller))
2545 {
2546 sx1 = sx2 = fixed;
2547 sy1 = y;
2548 sy2 = sy1 + nb->notebook.frame_height -
2549 nb->notebook.major_scroller_height;
2550 limit = nb->notebook.frame_height -
2551 MAX(0, (int)(nb->notebook.major_scroller_height -
2552 nb->notebook.back_page_size)) -
2553 nb->notebook.major_height -
2554 nb->notebook.shadow_thickness;
2555 y += nb->notebook.major_scroller_height + spacing;
2556 }
2557 else
2558 y += nb->notebook.shadow_thickness;
2559
2560 /* set arrow direction resource */
2561 prev = XmARROW_UP;
2562 next = XmARROW_DOWN;
2563 }
2564 else if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT &&
2565 nb->notebook.orientation == XmVERTICAL)
2566 {
2567 /* set starting position */
2568 x = nb->notebook.back_page_size;
2569 y = nb->notebook.real_binding_width + nb->notebook.frame_height;
2570 fixed = y + nb->notebook.back_page_size;
2571 limit = nb->notebook.frame_width -
2572 nb->notebook.major_width -
2573 nb->notebook.shadow_thickness;
2574 if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller))
2575 {
2576 sy1 = sy2 = fixed;
2577 sx1 = x;
2578 sx2 = sx1 + nb->notebook.frame_width -
2579 nb->notebook.major_scroller_width;
2580 limit = nb->notebook.frame_width -
2581 MAX(0, (int)(nb->notebook.major_scroller_width -
2582 nb->notebook.back_page_size)) -
2583 nb->notebook.major_width -
2584 nb->notebook.shadow_thickness;
2585 x += nb->notebook.major_scroller_width + spacing;
2586 }
2587 else
2588 x += nb->notebook.shadow_thickness;
2589
2590 /* set arrow direction resource */
2591 prev = XmARROW_LEFT;
2592 next = XmARROW_RIGHT;
2593 }
2594 else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT &&
2595 nb->notebook.orientation == XmHORIZONTAL)
2596 {
2597 /* set starting position */
2598 margin_w = NB_MAJOR_MAX(nb, nb->notebook.major_width,
2599 nb->notebook.major_scroller_width) +1;
2600 x = margin_w + nb->notebook.back_page_size - nb->notebook.major_width;
2601 y = nb->notebook.back_page_size;
2602 fixed = x - nb->notebook.back_page_size;
2603 limit = nb->notebook.frame_height -
2604 nb->notebook.major_height -
2605 nb->notebook.shadow_thickness;
2606 if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller))
2607 {
2608 sx1 = sx2 = margin_w - nb->notebook.minor_scroller_width;
2609 sy1 = y;
2610 sy2 = y + nb->notebook.frame_height -
2611 nb->notebook.major_scroller_height;
2612 limit = nb->notebook.frame_height -
2613 MAX(0, (int)(nb->notebook.major_scroller_height -
2614 nb->notebook.back_page_size)) -
2615 nb->notebook.major_height -
2616 nb->notebook.shadow_thickness;
2617 y += nb->notebook.major_scroller_height + spacing;
2618 }
2619 else
2620 y += nb->notebook.shadow_thickness;
2621
2622 /* set arrow direction resource */
2623 prev = XmARROW_UP;
2624 next = XmARROW_DOWN;
2625 }
2626 else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT &&
2627 nb->notebook.orientation == XmVERTICAL)
2628 {
2629 /* set starting position */
2630 margin_w = NB_MINOR_MAX(nb, nb->notebook.minor_width,
2631 nb->notebook.minor_scroller_width);
2632 x = margin_w + nb->notebook.frame_width - nb->notebook.major_width;
2633 y = nb->notebook.real_binding_width + nb->notebook.frame_height;
2634 fixed = y + nb->notebook.back_page_size;
2635 limit = margin_w + nb->notebook.back_page_size +
2636 nb->notebook.shadow_thickness;
2637 if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller))
2638 {
2639 sy1 = sy2 = fixed;
2640 sx1 = margin_w + nb->notebook.frame_width -
2641 nb->notebook.major_scroller_width;
2642 sx2 = margin_w;
2643 limit = margin_w +
2644 MAX(nb->notebook.back_page_size,
2645 nb->notebook.major_scroller_width) +
2646 nb->notebook.shadow_thickness;
2647 x -= nb->notebook.major_scroller_width + spacing;
2648 }
2649 else
2650 x -= spacing;
2651
2652 /* set arrow direction resource */
2653 prev = XmARROW_RIGHT;
2654 next = XmARROW_LEFT;
2655 }
2656 else if (nb->notebook.back_page_pos == XmTOP_RIGHT &&
2657 nb->notebook.orientation == XmHORIZONTAL)
2658 {
2659 /* set starting position */
2660 margin_h = NB_MINOR_MAX(nb, nb->notebook.minor_height,
2661 nb->notebook.minor_scroller_height);
2662 x = nb->notebook.real_binding_width + nb->notebook.frame_width;
2663 y = margin_h + nb->notebook.frame_height - nb->notebook.major_height;
2664 fixed = x + nb->notebook.back_page_size;
2665 limit = margin_h + nb->notebook.back_page_size +
2666 nb->notebook.shadow_thickness;
2667 if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller))
2668 {
2669 sx1 = sx2 = fixed;
2670 sy1 = margin_h + nb->notebook.frame_height -
2671 nb->notebook.minor_scroller_height;
2672 sy2 = margin_h;
2673 limit = margin_h +
2674 MAX(nb->notebook.back_page_size,
2675 nb->notebook.major_scroller_height) +
2676 nb->notebook.shadow_thickness;
2677 y -= nb->notebook.major_scroller_height + spacing;
2678 }
2679 else
2680 y -= spacing;
2681
2682 /* set arrow direction resource */
2683 prev = XmARROW_DOWN;
2684 next = XmARROW_UP;
2685 }
2686 else if (nb->notebook.back_page_pos == XmTOP_RIGHT &&
2687 nb->notebook.orientation == XmVERTICAL)
2688 {
2689 /* set starting position */
2690 margin_h = NB_MAJOR_MAX(nb, nb->notebook.major_height,
2691 nb->notebook.major_scroller_height) +1;
2692 x = nb->notebook.back_page_size;
2693 y = margin_h + nb->notebook.back_page_size - nb->notebook.major_height;
2694 fixed = margin_h - nb->notebook.major_height;
2695 limit = nb->notebook.frame_width -
2696 nb->notebook.major_width -
2697 nb->notebook.shadow_thickness;
2698 if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller))
2699 {
2700 sy1 = sy2 = margin_h - nb->notebook.major_scroller_height;
2701 sx1 = x;
2702 sx2 = nb->notebook.frame_width +
2703 nb->notebook.back_page_size -
2704 nb->notebook.major_scroller_width;
2705 limit = nb->notebook.frame_width -
2706 MAX(0, (int)(nb->notebook.major_scroller_width -
2707 nb->notebook.back_page_size)) -
2708 nb->notebook.major_width -
2709 nb->notebook.shadow_thickness;
2710 x += nb->notebook.major_scroller_width + spacing;
2711 }
2712 else
2713 x += nb->notebook.shadow_thickness;
2714
2715 /* set arrow direction resource */
2716 prev = XmARROW_LEFT;
2717 next = XmARROW_RIGHT;
2718 }
2719 else if (nb->notebook.back_page_pos == XmTOP_LEFT &&
2720 nb->notebook.orientation == XmHORIZONTAL)
2721 {
2722 /* set starting position */
2723 margin_w = NB_MAJOR_MAX(nb, nb->notebook.major_width,
2724 nb->notebook.major_scroller_width) +1;
2725 margin_h = NB_MINOR_MAX(nb, nb->notebook.minor_height,
2726 nb->notebook.minor_scroller_height) +1;
2727 x = margin_w + nb->notebook.back_page_size - nb->notebook.major_width;
2728 y = margin_h + nb->notebook.frame_height - nb->notebook.major_height;
2729 fixed = x - nb->notebook.back_page_size;
2730 limit = margin_h +
2731 nb->notebook.back_page_size +
2732 nb->notebook.shadow_thickness;
2733 if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller))
2734 {
2735 sx1 = sx2 = margin_w - nb->notebook.minor_scroller_width;
2736 sy1 = margin_h + nb->notebook.frame_height -
2737 nb->notebook.major_scroller_height;
2738 sy2 = margin_h;
2739 limit = margin_h +
2740 MAX(nb->notebook.back_page_size,
2741 nb->notebook.major_scroller_height) +
2742 nb->notebook.shadow_thickness;
2743 y -= nb->notebook.major_scroller_height + spacing;
2744 }
2745 else
2746 y -= spacing;
2747
2748 /* set arrow direction resource */
2749 prev = XmARROW_DOWN;
2750 next = XmARROW_UP;
2751 }
2752 else
2753 {
2754 /* set starting position */
2755 margin_w = NB_MINOR_MAX(nb, nb->notebook.minor_width,
2756 nb->notebook.minor_scroller_width) +1;
2757 margin_h = NB_MAJOR_MAX(nb, nb->notebook.major_height,
2758 nb->notebook.major_scroller_height) +1;
2759 x = margin_w + nb->notebook.frame_width - nb->notebook.major_width;
2760 y = margin_h + nb->notebook.back_page_size - nb->notebook.major_height;
2761 fixed = y - nb->notebook.back_page_size;
2762 limit = margin_w + nb->notebook.back_page_size +
2763 nb->notebook.shadow_thickness;
2764 if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller))
2765 {
2766 sy1 = sy2 = margin_h - nb->notebook.major_scroller_height;
2767 sx1 = margin_w + nb->notebook.frame_width -
2768 nb->notebook.major_scroller_width;
2769 sx2 = margin_w;
2770 limit = margin_w +
2771 MAX(nb->notebook.back_page_size,
2772 nb->notebook.major_scroller_width) +
2773 nb->notebook.shadow_thickness;
2774 x -= nb->notebook.major_scroller_width + spacing;
2775 }
2776 else
2777 x -= spacing;
2778
2779 /* set arrow direction resource */
2780 prev = XmARROW_RIGHT;
2781 next = XmARROW_LEFT;
2782 }
2783
2784
2785
2786 /*
2787 * Deal with previous top and current top tab shadowing
2788 */
2789
2790 /* Inform old top major to restore shadow_thickness */
2791 if (nb->notebook.old_top_major != NULL
2792 && nb->notebook.old_top_major != nb->notebook.top_major)
2793 {
2794 /* Protect against geometry requests during join changes */
2795 nb->notebook.in_setshadow = True;
2796
2797 /* Inform join-aware tab else restore shadow thickness */
2798 if (!UpdateJoinSide(nb, nb->notebook.old_top_major,
2799 XmMAJOR_TAB, (Dimension)0))
2800 {
2801 /* Hide the old top major shadow */
2802 HideShadowedTab(nb, nb->notebook.old_top_major);
2803
2804 /* Restore child shadow thickness */
2805 XtVaSetValues(nb->notebook.old_top_major,
2806 XmNshadowThickness, nb->notebook.major_shadow_thickness,
2807 NULL);
2808 }
2809
2810 /* Release protection against geometry requests */
2811 nb->notebook.in_setshadow = False;
2812 }
2813
2814
2815 /* Store & set new top major's shadow */
2816 if (nb->notebook.top_major != NULL)
2817 {
2818 /* Hide the top major shadow, as it may be moving (shown or hidden) */
2819 HideShadowedTab(nb, nb->notebook.top_major);
2820
2821 /* Protect against geometry requests during join changes */
2822 nb->notebook.in_setshadow = True;
2823
2824 /* Set shadow thickness of new top tab */
2825 if (!UpdateJoinSide(nb, nb->notebook.top_major,
2826 XmMAJOR_TAB, nb->notebook.shadow_thickness))
2827 {
2828 /* Save shadow_thickness of top tab, unless we already have */
2829 if (nb->notebook.top_major != nb->notebook.major_shadow_child)
2830 {
2831 XtVaGetValues(nb->notebook.top_major,
2832 XmNshadowThickness, &(nb->notebook.major_shadow_thickness),
2833 NULL);
2834 nb->notebook.major_shadow_child = nb->notebook.top_major;
2835 }
2836 else
2837 {
2838 /* CR 9903: The application may have set shadow_thickness. */
2839 Dimension current = 0;
2840 XtVaGetValues(nb->notebook.top_major,
2841 XmNshadowThickness, ¤t,
2842 NULL);
2843 if (current != 0)
2844 nb->notebook.major_shadow_thickness = current;
2845 }
2846
2847 /* Notebook will draw shadow for non-JoinSide trait tabs */
2848 XtVaSetValues(nb->notebook.top_major,
2849 XmNshadowThickness, 0,
2850 NULL);
2851 }
2852 else
2853 join_child = nb->notebook.top_major;
2854
2855 /* Release protection against geometry requests */
2856 nb->notebook.in_setshadow = False;
2857 }
2858 else
2859 /* There is no top tab so advance to the first back page line */
2860 {
2861 if (nb->notebook.major_pos == RIGHT)
2862 x += delta;
2863 else if (nb->notebook.major_pos == LEFT)
2864 x -= delta;
2865 else if (nb->notebook.major_pos == BOTTOM)
2866 y += delta;
2867 else /* if (nb->notebook.major_pos == TOP) */
2868 y -= delta;
2869 }
2870 /*
2871 * FIX for CDExc23791
2872 */
2873 total_major_tabs = 0;
2874 for (i = 0; i < nb->composite.num_children; i++)
2875 {
2876 child = nb->composite.children[i];
2877 nc = NotebookConstraint(child);
2878 if (NB_IS_CHILD_MAJOR(nc->child_type))
2879 total_major_tabs++;
2880 if ( child == nb->notebook.top_major)
2881 top_tab_count = total_major_tabs;
2882 }
2883 /*
2884 * Layout major tabs
2885 */
2886 tab_count = 0;
2887 for (i = 0; i < nb->composite.num_children; i++)
2888 {
2889 child = nb->composite.children[i];
2890 nc = NotebookConstraint(child);
2891
2892 if (NB_IS_CHILD_MAJOR(nc->child_type))
2893 {
2894 if (!nc->active)
2895 HideChild(child, instigator);
2896 else if (nc->page_number < first_major)
2897 {
2898 HideChild(child, instigator);
2899 gray_prev = False;
2900 }
2901 else if ((nb->notebook.minor_pos == BOTTOM && y > limit)
2902 || (nb->notebook.minor_pos == TOP && y < limit)
2903 || (nb->notebook.minor_pos == RIGHT && x > limit)
2904 || (nb->notebook.minor_pos == LEFT && x < limit))
2905 {
2906 HideChild(child, instigator);
2907 gray_next = False;
2908 }
2909 else
2910 {
2911 /* Display the tab */
2912 if ( current_tab < top_tab_count - 1 )
2913 {
2914 /*
2915 * FIX for CDExc23791
2916 */
2917 if (nb->notebook.orientation == XmHORIZONTAL)
2918 {
2919 if (nb->notebook.major_pos == RIGHT)
2920 tmpx = x + ( total_major_tabs + 1 - top_tab_count + current_tab) * delta;
2921 else
2922 tmpx = x - ( total_major_tabs + 1 - top_tab_count + current_tab) * delta;
2923 tmpy = y;
2924 }
2925 else
2926 {
2927 tmpx = x;
2928 if (nb->notebook.major_pos == TOP)
2929 tmpy = y - (total_major_tabs + 1 - top_tab_count + current_tab) * delta;
2930 else
2931 tmpy = y + (total_major_tabs + 1 - top_tab_count + current_tab) * delta;
2932 }
2933 }
2934 else
2935 {
2936 tmpx = x;
2937 tmpy = y;
2938 }
2939
2940 if (/*(nb->notebook.orientation == XmHORIZONTAL &&
2941 nc->page_number < top_major)
2942 ||*/ (nb->notebook.major_pos == RIGHT && tmpx > fixed)
2943 || (nb->notebook.major_pos == LEFT && tmpx < fixed))
2944 {
2945 tmpx = fixed;
2946 }
2947 else if (/*(nb->notebook.orientation == XmVERTICAL &&
2948 nc->page_number < top_major)
2949 ||*/ (nb->notebook.major_pos == BOTTOM && tmpy > fixed)
2950 || (nb->notebook.major_pos == TOP && tmpy < fixed))
2951 {
2952 tmpy = fixed;
2953 }
2954
2955 /* move joinSide top tab over to align with frame */
2956 if ((join_child && (join_child == child))
2957 || (nb->notebook.top_major
2958 && (nb->notebook.top_major == child)))
2959 {
2960 if (nb->notebook.major_pos == LEFT)
2961 tmpx = tmpx + nb->notebook.shadow_thickness;
2962 else if (nb->notebook.major_pos == RIGHT)
2963 tmpx = tmpx - nb->notebook.shadow_thickness;
2964 else if (nb->notebook.major_pos == TOP)
2965 tmpy = tmpy + nb->notebook.shadow_thickness;
2966 else /* (nb->notebook.major_pos == BOTTOM) */
2967 tmpy = tmpy - nb->notebook.shadow_thickness;
2968 }
2969
2970 /* Make tab visible */
2971 ShowChild(child, instigator, tmpx, tmpy,
2972 nb->notebook.major_width,
2973 nb->notebook.major_height);
2974 tab_count++;
2975 /* Calculate the next position */
2976 if (nb->notebook.minor_pos == BOTTOM)
2977 y += nb->notebook.major_height + spacing;
2978 else if (nb->notebook.minor_pos == TOP)
2979 y -= nb->notebook.major_height + spacing;
2980 else if (nb->notebook.minor_pos == RIGHT)
2981 x += nb->notebook.major_width + spacing;
2982 else /* (nb->notebook.minor_pos == LEFT) */
2983 x -= nb->notebook.major_width + spacing;
2984
2985 }
2986
2987 /* to the next back page line */
2988 if (nc->page_number >= top_major)
2989 {
2990 if (nb->notebook.major_pos == RIGHT)
2991 x += delta;
2992 else if (nb->notebook.major_pos == LEFT)
2993 x -= delta;
2994 else if (nb->notebook.major_pos == BOTTOM)
2995 y += delta;
2996 else
2997 y -= delta;
2998 }
2999 current_tab++;
3000 } /* if */
3001 } /* for */
3002
3003
3004 /*
3005 * Display the tab scrolling tab, if neccessary
3006 */
3007 if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller) && tab_count)
3008 {
3009
3010 /* set scroller's arrow directions */
3011 XtVaGetValues(nb->notebook.prev_major,
3012 XmNarrowDirection, &direction, NULL);
3013 if (direction != prev)
3014 XtVaSetValues(nb->notebook.prev_major,
3015 XmNarrowDirection, prev, NULL);
3016 XtVaGetValues(nb->notebook.next_major,
3017 XmNarrowDirection, &direction, NULL);
3018 if (direction != next)
3019 XtVaSetValues(nb->notebook.next_major,
3020 XmNarrowDirection, next, NULL);
3021
3022 /* Gray out scrollers, if necessary */
3023 if (gray_prev)
3024 XtSetSensitive(nb->notebook.prev_major, False);
3025 else
3026 XtSetSensitive(nb->notebook.prev_major, True);
3027
3028 if (gray_next)
3029 XtSetSensitive(nb->notebook.next_major, False);
3030 else
3031 XtSetSensitive(nb->notebook.next_major, True);
3032
3033 /* show the scrollers */
3034 ShowChild(nb->notebook.prev_major, instigator, sx1, sy1,
3035 nb->notebook.major_scroller_width,
3036 nb->notebook.major_scroller_height);
3037 ShowChild(nb->notebook.next_major, instigator, sx2, sy2,
3038 nb->notebook.major_scroller_width,
3039 nb->notebook.major_scroller_height);
3040 }
3041 else
3042 {
3043 HideChild(nb->notebook.prev_major, instigator);
3044 HideChild(nb->notebook.next_major, instigator);
3045 }
3046 }
3047
3048
3049 /*- LayoutMinorTabs ---------------------------------------------------------
3050
3051 Function to layout minor tabs
3052
3053 -----------------------------------------------------------------------------*/
3054 static void
LayoutMinorTabs(XmNotebookWidget nb,Widget instigator)3055 LayoutMinorTabs (
3056 XmNotebookWidget nb,
3057 Widget instigator)
3058 {
3059 XmNotebookConstraint nc; /* constraint pointer */
3060 Widget child; /* a major tab widget */
3061 Widget join_child = NULL; /* top minor and joinSide tab */
3062 int x, y, tmpx, tmpy; /* tab's geometry */
3063 int tab_count; /* # of tabs shown */
3064 int backpage_h; /* temporary backpage value */
3065 int margin_w, margin_h; /* temporary margin value */
3066 int sx1, sy1, sx2, sy2; /* tab scroller position */
3067 int fixed; /* back page fixed position */
3068 int limit; /* the last possible position */
3069 int spacing; /* major tab spacing */
3070 int status; /* minor tab drawing status */
3071 int top_major; /* page# of the top major tab */
3072 int first_minor, top_minor; /* page# of first and top minor tabs */
3073 unsigned char prev, next; /* for tab scroller arrow direction */
3074 Boolean gray_prev, gray_next; /* True if need to gray out scrollers */
3075 int i;
3076 unsigned char direction;
3077 int offset = 0;
3078 /*
3079 * Initialize
3080 */
3081 top_major = nb->notebook.top_major
3082 ? NotebookConstraint(nb->notebook.top_major)->page_number
3083 : nb->notebook.first_page_number - 1;
3084 first_minor = nb->notebook.first_minor
3085 ? NotebookConstraint(nb->notebook.first_minor)->page_number
3086 : nb->notebook.first_page_number - 1;
3087 top_minor = nb->notebook.top_minor
3088 ? NotebookConstraint(nb->notebook.top_minor)->page_number
3089 : nb->notebook.first_page_number - 1;
3090 gray_prev = gray_next = True;
3091 sx1 = sy1 = sx2 = sy2 = 0;
3092
3093 if ( nb->notebook.shadow_thickness == 0 )
3094 offset = 1;
3095
3096 /*
3097 * Determine tap spacing
3098 */
3099 spacing = MAX(nb->notebook.minor_spacing, nb->notebook.shadow_thickness);
3100
3101 /*
3102 * Determine tab positions
3103 */
3104 if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT
3105 && nb->notebook.orientation == XmHORIZONTAL)
3106 {
3107 /* set starting position */
3108 x = MAX((nb->notebook.real_binding_width + 1 + offset),
3109 nb->notebook.back_page_size);
3110 y = nb->notebook.frame_height;
3111 fixed = y + NB_MINOR_TAB_STEP(nb->notebook.back_page_size);
3112 limit = nb->notebook.real_binding_width +
3113 nb->notebook.frame_width -
3114 nb->notebook.minor_width -
3115 nb->notebook.shadow_thickness;
3116 if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller))
3117 {
3118 sy1 = sy2 = y + nb->notebook.back_page_size;
3119 sx1 = x;
3120 sx2 = nb->notebook.real_binding_width +
3121 nb->notebook.frame_width +
3122 nb->notebook.back_page_size -
3123 nb->notebook.minor_scroller_width;
3124 limit = nb->notebook.real_binding_width +
3125 nb->notebook.frame_width -
3126 nb->notebook.minor_width -
3127 nb->notebook.shadow_thickness -
3128 MAX(0, (int)(nb->notebook.minor_scroller_width -
3129 nb->notebook.back_page_size));
3130 x += nb->notebook.minor_scroller_width + spacing;
3131 }
3132 else
3133 x += nb->notebook.shadow_thickness;
3134
3135 /* set arrow direction resource */
3136 prev = XmARROW_LEFT;
3137 next = XmARROW_RIGHT;
3138 }
3139 else if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT
3140 && nb->notebook.orientation == XmVERTICAL)
3141 {
3142 /* set starting position */
3143 backpage_h = 1;
3144 if (nb->notebook.back_page_size > nb->notebook.real_binding_width)
3145 backpage_h = nb->notebook.back_page_size -
3146 nb->notebook.real_binding_width;
3147 x = nb->notebook.frame_width;
3148 y = nb->notebook.real_binding_width + backpage_h + offset;
3149 fixed = x + NB_MINOR_TAB_STEP(nb->notebook.back_page_size);
3150 limit = nb->notebook.real_binding_width +
3151 nb->notebook.frame_height -
3152 nb->notebook.minor_height -
3153 nb->notebook.shadow_thickness;
3154 if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller))
3155 {
3156 sx1 = sx2 = x + nb->notebook.back_page_size;
3157 sy1 = y;
3158 sy2 = nb->notebook.real_binding_width +
3159 nb->notebook.frame_height +
3160 nb->notebook.back_page_size -
3161 nb->notebook.minor_scroller_height;
3162 limit = nb->notebook.real_binding_width +
3163 nb->notebook.frame_height -
3164 MAX(0, (int)(nb->notebook.minor_scroller_height -
3165 nb->notebook.back_page_size)) -
3166 nb->notebook.minor_height -
3167 nb->notebook.shadow_thickness;
3168 y += nb->notebook.minor_scroller_height + spacing;
3169 }
3170 else
3171 y += nb->notebook.shadow_thickness;
3172
3173 /* set arrow direction resource */
3174 prev = XmARROW_UP;
3175 next = XmARROW_DOWN;
3176 }
3177 else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT
3178 && nb->notebook.orientation == XmHORIZONTAL)
3179 {
3180 /* set starting position */
3181 margin_w = NB_MAJOR_MAX(nb, nb->notebook.major_width,
3182 nb->notebook.major_scroller_width);
3183 x = margin_w +
3184 nb->notebook.back_page_size +
3185 nb->notebook.frame_width -
3186 MAX(0, (int)(nb->notebook.back_page_size -
3187 nb->notebook.real_binding_width)) -
3188 nb->notebook.minor_width - offset;
3189 y = nb->notebook.frame_height;
3190 fixed = y + NB_MINOR_TAB_STEP(nb->notebook.back_page_size);
3191 limit = margin_w +
3192 nb->notebook.back_page_size +
3193 nb->notebook.shadow_thickness;
3194 if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller))
3195 {
3196 sy1 = sy2 = y + nb->notebook.back_page_size;
3197 sx1 = margin_w + nb->notebook.back_page_size +
3198 nb->notebook.frame_width -
3199 MAX(0, (int)(nb->notebook.back_page_size -
3200 nb->notebook.real_binding_width)) -
3201 nb->notebook.minor_scroller_width;
3202 sx2 = margin_w;
3203 limit = margin_w +
3204 MAX(nb->notebook.minor_scroller_width,
3205 nb->notebook.back_page_size) +
3206 nb->notebook.shadow_thickness;
3207 x -= nb->notebook.minor_scroller_width + spacing;
3208 }
3209 else
3210 x -= nb->notebook.shadow_thickness;
3211
3212 /* set arrow direction resource */
3213 prev = XmARROW_RIGHT;
3214 next = XmARROW_LEFT;
3215 }
3216 else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT
3217 && nb->notebook.orientation == XmVERTICAL)
3218 {
3219 /* set starting position */
3220 margin_w = NB_MINOR_MAX(nb, nb->notebook.minor_width,
3221 nb->notebook.minor_scroller_width) +1;
3222 x = margin_w + nb->notebook.back_page_size - nb->notebook.minor_width;
3223 y = MAX((nb->notebook.real_binding_width + 1 + offset),
3224 nb->notebook.back_page_size);
3225 fixed = margin_w +
3226 NB_MINOR_TAB_STEP(nb->notebook.back_page_size) -
3227 nb->notebook.minor_width;
3228 limit = nb->notebook.real_binding_width +
3229 nb->notebook.frame_height -
3230 nb->notebook.minor_height -
3231 nb->notebook.shadow_thickness;
3232 if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller))
3233 {
3234 sx1 = sx2 = margin_w - nb->notebook.minor_scroller_width;
3235 sy1 = y;
3236 sy2 = nb->notebook.real_binding_width +
3237 nb->notebook.frame_height +
3238 nb->notebook.back_page_size -
3239 nb->notebook.minor_scroller_height;
3240 limit = nb->notebook.real_binding_width +
3241 nb->notebook.frame_height -
3242 MAX(0, (int)(nb->notebook.minor_scroller_height -
3243 nb->notebook.back_page_size)) -
3244 nb->notebook.minor_height -
3245 nb->notebook.shadow_thickness;
3246 y += nb->notebook.minor_scroller_height + spacing;
3247 }
3248 else
3249 y += nb->notebook.shadow_thickness;
3250
3251 /* set arrow direction resource */
3252 prev = XmARROW_UP;
3253 next = XmARROW_DOWN;
3254 }
3255 else if (nb->notebook.back_page_pos == XmTOP_RIGHT
3256 && nb->notebook.orientation == XmHORIZONTAL)
3257 {
3258 /* set starting position */
3259 margin_h = NB_MINOR_MAX(nb, nb->notebook.minor_height,
3260 nb->notebook.minor_scroller_height) + 1;
3261 x = MAX((nb->notebook.real_binding_width + 1 + offset),
3262 nb->notebook.back_page_size);
3263 y = margin_h + nb->notebook.back_page_size - nb->notebook.minor_height;
3264 fixed = margin_h + NB_MINOR_TAB_STEP(nb->notebook.back_page_size) -
3265 nb->notebook.minor_height;
3266 limit = nb->notebook.real_binding_width +
3267 nb->notebook.frame_width -
3268 nb->notebook.minor_width -
3269 nb->notebook.shadow_thickness;
3270 if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller))
3271 {
3272 sy1 = sy2 = margin_h - nb->notebook.minor_scroller_height;
3273 sx1 = x;
3274 sx2 = nb->notebook.real_binding_width +
3275 nb->notebook.frame_width +
3276 nb->notebook.back_page_size -
3277 nb->notebook.minor_scroller_width;
3278 limit = nb->notebook.real_binding_width +
3279 nb->notebook.frame_width -
3280 MAX(0, (int)(nb->notebook.minor_scroller_width -
3281 nb->notebook.back_page_size)) -
3282 nb->notebook.minor_width -
3283 nb->notebook.shadow_thickness;
3284 x += nb->notebook.minor_scroller_width + spacing;
3285 }
3286 else
3287 x += nb->notebook.shadow_thickness;
3288
3289 /* set arrow direction resource */
3290 prev = XmARROW_LEFT;
3291 next = XmARROW_RIGHT;
3292 }
3293 else if (nb->notebook.back_page_pos == XmTOP_RIGHT
3294 && nb->notebook.orientation == XmVERTICAL)
3295 {
3296 /* set starting position */
3297 backpage_h = 0;
3298 if (nb->notebook.back_page_size > nb->notebook.real_binding_width)
3299 backpage_h = nb->notebook.back_page_size -
3300 nb->notebook.real_binding_width;
3301 margin_h = NB_MAJOR_MAX(nb, nb->notebook.major_height,
3302 nb->notebook.major_scroller_height);
3303 x = nb->notebook.frame_width;
3304 y = margin_h + nb->notebook.back_page_size +
3305 nb->notebook.frame_height -
3306 nb->notebook.minor_height - backpage_h - offset;
3307 fixed = x + NB_MINOR_TAB_STEP(nb->notebook.back_page_size);
3308 limit = margin_h + nb->notebook.back_page_size +
3309 nb->notebook.shadow_thickness;
3310 if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller))
3311 {
3312 sx1 = sx2 = x + nb->notebook.back_page_size;
3313 sy1 = margin_h + nb->notebook.back_page_size +
3314 nb->notebook.frame_height -
3315 nb->notebook.minor_scroller_height - backpage_h;
3316 sy2 = margin_h;
3317 limit = margin_h +
3318 MAX(nb->notebook.back_page_size,
3319 nb->notebook.minor_scroller_height) +
3320 nb->notebook.shadow_thickness;
3321 y -= (nb->notebook.minor_scroller_height + spacing);
3322 }
3323 else
3324 y -= nb->notebook.shadow_thickness;
3325
3326 /* set arrow direction resource */
3327 prev = XmARROW_DOWN;
3328 next = XmARROW_UP;
3329 }
3330 else if (nb->notebook.back_page_pos == XmTOP_LEFT
3331 && nb->notebook.orientation == XmHORIZONTAL)
3332 {
3333 /* set starting position */
3334 margin_w = NB_MAJOR_MAX(nb, nb->notebook.major_width,
3335 nb->notebook.major_scroller_width);
3336 margin_h = NB_MINOR_MAX(nb, nb->notebook.minor_height,
3337 nb->notebook.minor_scroller_height) +1;
3338 x = margin_w +
3339 nb->notebook.back_page_size +
3340 nb->notebook.frame_width -
3341 MAX(0, (int)(nb->notebook.back_page_size -
3342 nb->notebook.real_binding_width)) -
3343 nb->notebook.minor_width - offset;
3344 y = margin_h + nb->notebook.back_page_size - nb->notebook.minor_height;
3345 fixed = y - NB_MINOR_TAB_STEP(nb->notebook.back_page_size);
3346 limit = margin_w +
3347 nb->notebook.back_page_size +
3348 nb->notebook.shadow_thickness;
3349 if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller))
3350 {
3351 sy1 = sy2 = margin_h - nb->notebook.minor_scroller_height;
3352 sx1 = margin_w +
3353 nb->notebook.back_page_size +
3354 nb->notebook.frame_width -
3355 MAX(0, (int)(nb->notebook.back_page_size -
3356 nb->notebook.real_binding_width)) -
3357 nb->notebook.minor_scroller_width;
3358 sx2 = margin_w;
3359 limit = margin_w +
3360 MAX(nb->notebook.minor_scroller_width,
3361 nb->notebook.back_page_size) +
3362 nb->notebook.shadow_thickness;
3363 x -= nb->notebook.minor_scroller_width + spacing;
3364 }
3365 else
3366 x -= nb->notebook.shadow_thickness;
3367
3368 /* set arrow direction resource */
3369 prev = XmARROW_RIGHT;
3370 next = XmARROW_LEFT;
3371 }
3372 else /* if (nb->notebook.back_page_pos == XmTOP_LEFT
3373 && nb->notebook.orientation == XmVERTICAL) */
3374 {
3375 /* set starting position */
3376 margin_w = NB_MINOR_MAX(nb, nb->notebook.minor_width,
3377 nb->notebook.minor_scroller_width) + 1;
3378 margin_h = NB_MAJOR_MAX(nb, nb->notebook.major_height,
3379 nb->notebook.major_scroller_height);
3380 x = margin_w + nb->notebook.back_page_size - nb->notebook.minor_width;
3381 y = margin_h +
3382 nb->notebook.back_page_size +
3383 nb->notebook.frame_height -
3384 nb->notebook.minor_height -
3385 MAX(0, (int)(nb->notebook.back_page_size -
3386 nb->notebook.real_binding_width)) - offset;
3387 fixed = x - NB_MINOR_TAB_STEP(nb->notebook.back_page_size);
3388 limit = margin_h + nb->notebook.back_page_size +
3389 nb->notebook.shadow_thickness;
3390 if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller))
3391 {
3392 sx1 = sx2 = margin_w - nb->notebook.minor_scroller_width;
3393 sy1 = margin_h +
3394 nb->notebook.back_page_size +
3395 nb->notebook.frame_height -
3396 MAX(0, (int)(nb->notebook.back_page_size -
3397 nb->notebook.real_binding_width)) -
3398 nb->notebook.minor_scroller_height;
3399 sy2 = margin_h;
3400 limit = margin_h +
3401 MAX(nb->notebook.back_page_size,
3402 nb->notebook.minor_scroller_height) +
3403 nb->notebook.shadow_thickness;
3404 y -= nb->notebook.minor_scroller_height + spacing;
3405 }
3406 else
3407 y -= nb->notebook.shadow_thickness;
3408
3409 /* set arrow direction resource */
3410 prev = XmARROW_DOWN;
3411 next = XmARROW_UP;
3412 }
3413
3414 /*
3415 * Deal with previous top and current top tab shadowing
3416 */
3417
3418 /* Inform old top minor to restore shadow_thickness */
3419 if (nb->notebook.old_top_minor != NULL
3420 && nb->notebook.old_top_minor != nb->notebook.top_minor)
3421 {
3422 /* Protect against geometry requests during join changes */
3423 nb->notebook.in_setshadow = True;
3424
3425 /* Inform join-aware tab else restore shadow thickness */
3426 if (!UpdateJoinSide(nb, nb->notebook.old_top_minor,
3427 XmMINOR_TAB, (Dimension)0))
3428 {
3429 /* Hide the old top minor shadow */
3430 HideShadowedTab(nb, nb->notebook.old_top_minor);
3431
3432 /* Restore the old top minor shadow thickness */
3433 XtVaSetValues(nb->notebook.old_top_minor,
3434 XmNshadowThickness, nb->notebook.minor_shadow_thickness,
3435 NULL);
3436 }
3437
3438 /* Release protection against geometry requests */
3439 nb->notebook.in_setshadow = False;
3440 }
3441
3442
3443 /* Store & set new top minor's shadow */
3444 if (nb->notebook.top_minor != NULL)
3445 {
3446 /* Hide the top minor shadow, as it may be moving (shown or hidden) */
3447 HideShadowedTab(nb, nb->notebook.top_minor);
3448
3449 /* Protect against geometry requests during join changes */
3450 nb->notebook.in_setshadow = True;
3451
3452 /* Set shadow thickness of new top tab */
3453 if (!UpdateJoinSide(nb, nb->notebook.top_minor,
3454 XmMINOR_TAB, nb->notebook.shadow_thickness))
3455 {
3456 /* Save shadow_thickness of top tab, unless we already have */
3457 if (nb->notebook.top_minor != nb->notebook.minor_shadow_child)
3458 {
3459 /* Save shadow_thickness of top tab, unless already saved */
3460 XtVaGetValues(nb->notebook.top_minor,
3461 XmNshadowThickness, &(nb->notebook.minor_shadow_thickness),
3462 NULL);
3463 nb->notebook.minor_shadow_child = nb->notebook.top_minor;
3464 }
3465 else
3466 {
3467 /* CR 9903: The application may have set shadow_thickness. */
3468 Dimension current = 0;
3469 XtVaGetValues(nb->notebook.top_minor,
3470 XmNshadowThickness, ¤t,
3471 NULL);
3472 if (current != 0)
3473 nb->notebook.minor_shadow_thickness = current;
3474 }
3475
3476 /* Notebook will draw shadow */
3477 XtVaSetValues(nb->notebook.top_minor,
3478 XmNshadowThickness, 0,
3479 NULL);
3480 }
3481 else
3482 join_child = nb->notebook.top_minor;
3483
3484 /* Release protection against geometry requests */
3485 nb->notebook.in_setshadow = False;
3486 }
3487
3488
3489 /*
3490 * Layout major tabs
3491 */
3492 status = TAB_DRAW;
3493 tab_count = 0;
3494 for (i = 0; i < nb->composite.num_children; i++)
3495 {
3496 child = nb->composite.children[i];
3497 nc = NotebookConstraint(child);
3498
3499 if (first_minor < nb->notebook.first_page_number
3500 || (nc->active
3501 && NB_IS_CHILD_MAJOR(nc->child_type)
3502 && (status == TAB_DRAWING || nc->page_number > first_minor)))
3503 status = TAB_DRAWN;
3504
3505 if (NB_IS_CHILD_MINOR(nc->child_type))
3506 {
3507 if (!nc->active || status == TAB_DRAWN)
3508 HideChild(child, instigator);
3509
3510 else if (nc->page_number < first_minor)
3511 {
3512 if (nc->page_number >= top_major)
3513 gray_prev = False;
3514 HideChild(child, instigator);
3515 }
3516 else if ((nb->notebook.binding_pos == LEFT && x > limit)
3517 || (nb->notebook.binding_pos == RIGHT && x < limit)
3518 || (nb->notebook.binding_pos == TOP && y > limit)
3519 || (nb->notebook.binding_pos == BOTTOM && y < limit))
3520 {
3521 gray_next = False;
3522 HideChild(child, instigator);
3523 }
3524 else
3525 {
3526 /* Display the tab */
3527 status = TAB_DRAWING;
3528 tmpx = x;
3529 tmpy = y;
3530 if (nc->page_number != top_minor)
3531 {
3532 if (nb->notebook.orientation == XmHORIZONTAL)
3533 tmpy = fixed;
3534 else
3535 tmpx = fixed;
3536 }
3537
3538 /* move joinSide top tab over to align with frame */
3539 if ((join_child && (join_child == child))
3540 || (nb->notebook.top_minor
3541 && (nb->notebook.top_minor == child)))
3542 {
3543 if (nb->notebook.minor_pos == LEFT)
3544 tmpx = tmpx + nb->notebook.shadow_thickness;
3545 else if (nb->notebook.minor_pos == RIGHT)
3546 tmpx = tmpx - nb->notebook.shadow_thickness;
3547 else if (nb->notebook.minor_pos == TOP)
3548 tmpy = tmpy + nb->notebook.shadow_thickness;
3549 else if (nb->notebook.minor_pos == BOTTOM)
3550 tmpy = tmpy - nb->notebook.shadow_thickness;
3551 }
3552
3553 /* Make tab visible */
3554 ShowChild(child, instigator, tmpx, tmpy,
3555 nb->notebook.minor_width,
3556 nb->notebook.minor_height);
3557 tab_count++;
3558
3559 /* Calculate the next position */
3560 if (nb->notebook.binding_pos == LEFT)
3561 x += nb->notebook.minor_width + spacing;
3562 else if (nb->notebook.binding_pos == RIGHT)
3563 x -= nb->notebook.minor_width + spacing;
3564 else if (nb->notebook.binding_pos == TOP)
3565 y += nb->notebook.minor_height + spacing;
3566 else
3567 y -= nb->notebook.minor_height + spacing;
3568
3569 }
3570 }
3571 }
3572
3573
3574 /* display the tab scrolling tab if neccessary */
3575 if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller) && tab_count)
3576 {
3577
3578 /* set scroller's arrow directions */
3579 XtVaGetValues(nb->notebook.prev_minor,
3580 XmNarrowDirection, &direction, NULL);
3581 if (direction != prev)
3582 XtVaSetValues(nb->notebook.prev_minor,
3583 XmNarrowDirection, prev, NULL);
3584 XtVaGetValues(nb->notebook.next_minor,
3585 XmNarrowDirection, &direction, NULL);
3586 if (direction != next)
3587 XtVaSetValues(nb->notebook.next_minor,
3588 XmNarrowDirection, next, NULL);
3589
3590 /* gray out scrollers if necessary */
3591 if (gray_prev)
3592 XtSetSensitive(nb->notebook.prev_minor, False);
3593 else
3594 XtSetSensitive(nb->notebook.prev_minor, True);
3595 if (gray_next)
3596 XtSetSensitive(nb->notebook.next_minor, False);
3597 else
3598 XtSetSensitive(nb->notebook.next_minor, True);
3599
3600 /* show the scrollers */
3601 ShowChild(nb->notebook.prev_minor, instigator, sx1, sy1,
3602 nb->notebook.minor_scroller_width,
3603 nb->notebook.minor_scroller_height);
3604 ShowChild(nb->notebook.next_minor, instigator, sx2, sy2,
3605 nb->notebook.minor_scroller_width,
3606 nb->notebook.minor_scroller_height);
3607 }
3608 else
3609 {
3610 HideChild(nb->notebook.prev_minor, instigator);
3611 HideChild(nb->notebook.next_minor, instigator);
3612 }
3613 }
3614
3615
3616 /*- ResetTopPointers --------------------------------------------------------
3617
3618 Function to calculate and update needed information to perform
3619 layout for major and minor tabs, and the tab scroller.
3620
3621 Uses instance state:
3622 notebook.current_page_number
3623
3624 Updates instance state:
3625
3626 notebook.first_major - page# of the first visible major tab
3627 notebook.first_minor - page# of the first visible minor tab
3628 notebook.top_major - page# of the currently active major tab
3629 notebook.top_minor - page# of the currently active minor tab
3630 notebook.need_scroller - tab scroller necessary, where
3631 XmNONE indicates none,
3632 XmMAJOR_TAB_SCROLLER indicates major only,
3633 XmMINOR_TAB_SCROLLER indicates minor only,
3634 XmTAB_SCROLLER indicates both are needed.
3635
3636 Called from:
3637 LayoutChildren(), when performing layout
3638 GotoPage(), when changing the top pages
3639 FlipTabs(), when tab scrolling are activated
3640 TraverseTab(), when tab traverse actions are activated
3641
3642
3643 Parameters:
3644 IN reason - Why was this routine called?
3645 where
3646 XmNONE = reset all information
3647 XmPAGE = reset due to a page navigation (general)
3648 XmPAGE_SCROLLER = reset due to navigating via the page scroller
3649 XmMAJOR_TAB = reset due to activating a minor tab
3650 XmMINOR_TAB = reset due to activating a major tab
3651 XmMAJOR_TAB_SCROLLER = reset due to major scroller activation
3652 XmMINOR_TAB_SCROLLER = reset due to minor scroller activation
3653
3654 IN scroll - What type of scrolling
3655 where
3656 _NEXT = scroll to the next major/minor tab
3657 _PREV = scroll to the previous major/minor tab
3658 _HOME = scroll to the first major/minor tab
3659 _END = scroll to the last major/minor tab
3660 (only used for reason == NB_IS_CHILD_MAJOR_SCROLLER or
3661 NB_IS_CHILD_MINOR_SCROLLER)
3662
3663 -----------------------------------------------------------------------------*/
3664 static void
ResetTopPointers(XmNotebookWidget nb,unsigned char reason,int scroll)3665 ResetTopPointers (
3666 XmNotebookWidget nb,
3667 unsigned char reason,
3668 int scroll)
3669 {
3670 XmNotebookConstraint nc; /* constraint pointer */
3671 Widget child; /* a tab widget */
3672 int i; /* index */
3673 int spacing; /* tab spacing */
3674 int half;
3675 int count; /* temporary counting */
3676 Dimension frame_dim,
3677 tab_dim,
3678 scroller_dim; /* temporary w/h */
3679
3680 /* major tab information */
3681 Widget start_major; /* the very first major tab */
3682 Widget top_major; /* the currently major tab */
3683 Widget next_major; /* the next major tab of first_major */
3684 Widget prev_major; /* the prev major tab of first_major */
3685 int first_major_page; /* page# of the first visible major tab */
3686 int top_major_page; /* page# of the current major tab */
3687 int top_major_idx; /* top major tab's index in the child array */
3688 int num_major; /* # of major tabs */
3689 int num_visible_major; /* # of visible major tabs */
3690 int num_rest_major; /* # of next major tabs of the current page */
3691 int num_next_major; /* # of next major tabs of first_major */
3692 int num_prev_major; /* # of prev major tabs of first_major */
3693
3694 /* minor tab information */
3695 Widget start_minor; /* the first minor tab in the current major */
3696 Widget top_minor; /* the current minor tab */
3697 Widget next_minor; /* the next minor tab of first_minor */
3698 Widget prev_minor; /* the prev minor tab of first_minor */
3699 int first_minor_page; /* page# of the first visible minor tab */
3700 int top_minor_page; /* page# of the current minor tab */
3701 int top_minor_idx; /* top minor tab's index in the child array */
3702 int start_minor_idx; /* start minor tab's index in the child array */
3703 int end_minor_idx; /* end minor tab's index in the child array */
3704 int num_minor; /* # of minor tabs */
3705 int num_visible_minor; /* # of visible minor tabs */
3706 int num_rest_minor; /* # of next minor tabs of the current page */
3707 int num_next_minor; /* # of next minor tabs of first_minor */
3708 int num_prev_minor; /* # of prev minor tabs of first_minor */
3709
3710
3711 /*
3712 * Calculate general tab information, based on the current_page_number.
3713 */
3714
3715 /* Major tab */
3716 first_major_page = nb->notebook.first_major
3717 ? NotebookConstraint(nb->notebook.first_major)->page_number
3718 : nb->notebook.first_page_number - 1;
3719 top_major_page = nb->notebook.first_page_number - 1;
3720 top_major_idx = -1;
3721 start_major = top_major = next_major = prev_major = NULL;
3722 num_major = num_rest_major = num_next_major = num_prev_major = 0;
3723
3724 for (i=0; i < nb->composite.num_children; i++)
3725 {
3726 child = nb->composite.children[i];
3727 nc = NotebookConstraint(child);
3728 if (nc->active && NB_IS_CHILD_MAJOR(nc->child_type))
3729 {
3730 if (!start_major)
3731 /* Mark the very first tab */
3732 start_major = child;
3733
3734 if (nc->page_number <= nb->notebook.current_page_number)
3735 {
3736 /* Mark the closest tab to the current page */
3737 top_major = child;
3738 top_major_page = nc->page_number;
3739 top_major_idx = i;
3740 }
3741 else
3742 /* Count of tabs past the current page */
3743 num_rest_major++;
3744
3745 if (nc->page_number < first_major_page)
3746 {
3747 /* Mark the closest previous tab to the first visible tab */
3748 prev_major = child;
3749 /* Count of tabs prior to the current page */
3750 num_prev_major++;
3751 }
3752 else if (nc->page_number > first_major_page)
3753 {
3754 if (!num_next_major)
3755 /* Mark the closest next tab to the current page */
3756 next_major = child;
3757 /* Count of tabs after the current page */
3758 num_next_major++;
3759 }
3760
3761 /* Count of all tabs */
3762 num_major++;
3763 }
3764 }
3765
3766 /* Minor tab */
3767 first_minor_page = nb->notebook.first_minor
3768 ? NotebookConstraint(nb->notebook.first_minor)->page_number
3769 : nb->notebook.first_page_number - 1;
3770 top_minor_page = nb->notebook.first_page_number - 1;
3771 top_minor_idx = -1;
3772 start_minor_idx = end_minor_idx = -1;
3773 start_minor = top_minor = next_minor = prev_minor = NULL;
3774 num_minor = num_rest_minor = num_next_minor = num_prev_minor = 0;
3775 for (i = 0; i < nb->composite.num_children; i++)
3776 {
3777 child = nb->composite.children[i];
3778 nc = NotebookConstraint(child);
3779 if (nc->active)
3780 {
3781 /* Break out when next major tab section is reached */
3782 if ( nc->page_number > top_major_page
3783 && NB_IS_CHILD_MAJOR(nc->child_type) )
3784 break;
3785
3786 /* This minor tab is in the current major tab section */
3787 if ( nc->page_number >= top_major_page
3788 && NB_IS_CHILD_MINOR(nc->child_type) )
3789 {
3790 if (!num_minor)
3791 {
3792 /* Mark the first tab in this section */
3793 start_minor = child;
3794 start_minor_idx = i;
3795 }
3796 if (nc->page_number <= nb->notebook.current_page_number)
3797 {
3798 /* Mark the closest tab to the current page */
3799 top_minor = child;
3800 top_minor_page = nc->page_number;
3801 top_minor_idx = i;
3802 }
3803 else
3804 {
3805 /* Count of tabs past the current page */
3806 num_rest_minor++;
3807 }
3808 if (nc->page_number < first_minor_page)
3809 {
3810 /* Mark the closest previous tab to the first visible tab */
3811 prev_minor = child;
3812 num_prev_minor++;
3813 }
3814 else if (nc->page_number > first_minor_page)
3815 {
3816 if (!num_next_minor)
3817 {
3818 /* Mark the closest next tab to the current page */
3819 next_minor = child;
3820 }
3821 /* Count of tabs after the current page */
3822 num_next_minor++;
3823 }
3824
3825 end_minor_idx = i;
3826 num_minor++;
3827 }
3828 }
3829 }
3830
3831
3832 /*
3833 * Find the number of possibly visible tabs (num_visible_xxx), and
3834 * find whether the tab scroller is needed (notebook.need_scroller)
3835 */
3836 nb->notebook.need_scroller = XmNONE;
3837
3838 /* Major tab */
3839 if (nb->notebook.orientation == XmHORIZONTAL)
3840 {
3841 frame_dim = nb->notebook.frame_height;
3842 tab_dim = MAX(nb->notebook.major_height, 1); /* Avoid div 0 */
3843 scroller_dim = nb->notebook.major_scroller_height;
3844 }
3845 else /* (nb->notebook.orientation == XmVERTICAL) */
3846 {
3847 frame_dim = nb->notebook.frame_width;
3848 tab_dim = MAX(nb->notebook.major_width, 1); /* Avoid div 0 */
3849 scroller_dim = nb->notebook.major_scroller_width;
3850 }
3851 spacing = MAX(nb->notebook.major_spacing, nb->notebook.shadow_thickness);
3852 num_visible_major = (int)(frame_dim -
3853 nb->notebook.back_page_size -
3854 nb->notebook.shadow_thickness) /
3855 (int)(tab_dim + spacing);
3856 if (num_visible_major < num_major)
3857 {
3858 nb->notebook.need_scroller = XmMAJOR_TAB_SCROLLER;
3859 num_visible_major = (int)(frame_dim -
3860 nb->notebook.back_page_size -
3861 scroller_dim -
3862 MAX(0, (int)(scroller_dim -
3863 nb->notebook.back_page_size)) -
3864 nb->notebook.shadow_thickness ) /
3865 (int)(tab_dim + spacing);
3866 }
3867
3868 /* Minor tab */
3869 if (nb->notebook.orientation == XmHORIZONTAL)
3870 {
3871 frame_dim = nb->notebook.frame_width;
3872 tab_dim = MAX(nb->notebook.minor_width, 1); /* Avoid div 0 */
3873 scroller_dim = nb->notebook.minor_scroller_width;
3874 }
3875 else /* (nb->notebook.orientation == XmVERTICAL) */
3876 {
3877 frame_dim = nb->notebook.frame_height;
3878 tab_dim = MAX(nb->notebook.minor_height, 1); /* Avoid div 0 */
3879 scroller_dim = nb->notebook.minor_scroller_height;
3880 }
3881 spacing = MAX(nb->notebook.minor_spacing, nb->notebook.shadow_thickness);
3882 num_visible_minor = (int)(frame_dim -
3883 MAX(0, (int)(nb->notebook.back_page_size -
3884 nb->notebook.real_binding_width)) -
3885 nb->notebook.shadow_thickness) /
3886 (int)(tab_dim + spacing);
3887 if (num_visible_minor < num_minor)
3888 {
3889 if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller))
3890 nb->notebook.need_scroller = XmTAB_SCROLLER;
3891 else
3892 nb->notebook.need_scroller = XmMINOR_TAB_SCROLLER;
3893 num_visible_minor = (int)(frame_dim -
3894 MAX(0, (int)(nb->notebook.back_page_size -
3895 nb->notebook.real_binding_width)) -
3896 scroller_dim -
3897 MAX(0, (int)(scroller_dim -
3898 nb->notebook.back_page_size)) -
3899 nb->notebook.shadow_thickness) /
3900 (int)(tab_dim + spacing);
3901 }
3902
3903
3904 /*
3905 * If tab scrolling, then determine first tab but leave top tab alone.
3906 */
3907
3908 /* Major tab */
3909 if (NB_IS_CHILD_MAJOR_SCROLLER(reason))
3910 {
3911 if (scroll == _NEXT)
3912 {
3913 /* If there is a next non-visible tab(s), move up one */
3914 if (num_next_major >= num_visible_major)
3915 nb->notebook.first_major = next_major;
3916 }
3917 else if (scroll == _PREVIOUS)
3918 {
3919 /* If there is a prev non-visible tab(s), move back one */
3920 if (num_prev_major > 0)
3921 nb->notebook.first_major = prev_major;
3922 }
3923 else if (scroll == _HOME)
3924 {
3925 /* If there is a starting tab, move to it */
3926 if (start_major)
3927 nb->notebook.first_major = start_major;
3928 }
3929 else if (scroll == _END)
3930 {
3931 /* Back up from the last tab "num_visible_major" tabs */
3932 for (count = num_visible_major,i = nb->composite.num_children -1;
3933 i >= 0 && count > 0; i--)
3934 {
3935 child = nb->composite.children[i];
3936 nc = NotebookConstraint(child);
3937 if (nc->active && NB_IS_CHILD_MAJOR(nc->child_type))
3938 {
3939 nb->notebook.first_major = child;
3940 count--;
3941 }
3942 }
3943 }
3944 return;
3945 }
3946
3947 /* Minor tab */
3948 if (NB_IS_CHILD_MINOR_SCROLLER(reason))
3949 {
3950 if (scroll == _NEXT)
3951 {
3952 if (num_next_minor >= num_visible_minor)
3953 nb->notebook.first_minor = next_minor;
3954 }
3955 else if (scroll == _PREVIOUS)
3956 {
3957 if (num_prev_minor > 0)
3958 nb->notebook.first_minor = prev_minor;
3959 }
3960 else if (scroll == _HOME)
3961 {
3962 nb->notebook.first_minor = start_minor;
3963 }
3964 else if (scroll == _END)
3965 {
3966 for (count = num_visible_minor,i = end_minor_idx;
3967 i >= 0 && i >= start_minor_idx && count > 0; i--)
3968 {
3969 child = nb->composite.children[i];
3970 nc = NotebookConstraint(child);
3971 if (nc->active && NB_IS_CHILD_MINOR(nc->child_type))
3972 {
3973 nb->notebook.first_minor = child;
3974 count--;
3975 }
3976 }
3977 }
3978 return;
3979 }
3980
3981
3982 /*
3983 * If going to a new page, then determine if we need to scroll
3984 * the tabs to make the top major/minor tabs visible
3985 */
3986 if (NB_IS_CHILD_PAGE(reason)
3987 || NB_IS_CHILD_PAGE_SCROLLER(reason)
3988 || NB_IS_CHILD_MAJOR(reason)
3989 || NB_IS_CHILD_MINOR(reason))
3990 {
3991 if (top_major && (top_major != nb->notebook.top_major))
3992 {
3993 if (NB_IS_VISIBLE(top_major))
3994 reason = XmMAJOR_TAB;
3995 }
3996 else if (top_minor && (top_minor != nb->notebook.top_minor))
3997 {
3998 if (NB_IS_VISIBLE(top_minor))
3999 reason = XmMINOR_TAB;
4000 }
4001 }
4002
4003 /*
4004 * Set new top major/minor tabs
4005 */
4006 nb->notebook.old_top_major = nb->notebook.top_major;
4007 nb->notebook.top_major = top_major;
4008
4009 nb->notebook.old_top_minor = nb->notebook.top_minor;
4010 nb->notebook.top_minor = top_minor;
4011
4012
4013 /*
4014 * Determine new first tab for the new top tab.
4015 * If apparently activated by a minor tab, we don't need to do anything
4016 * because the top major and minor must be visible .
4017 * If apparently activated by a major tab, we don't need to do anything.
4018 */
4019
4020 /* A page change NOT caused by a major tab activiation */
4021 if (!NB_IS_CHILD_MAJOR(reason) && !NB_IS_CHILD_MINOR(reason))
4022 {
4023 /* Set the first tab to the starting tab, if we do not need a page
4024 scroller or if the calculated top tab page number is less than
4025 the first page number */
4026 if (!NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller)
4027 || (top_major_page <= nb->notebook.first_page_number))
4028 nb->notebook.first_major = start_major;
4029
4030 /* Set the first tab to the calculated top tab, if it is the
4031 only one that might be visible */
4032 else if (num_visible_major <= 1)
4033 nb->notebook.first_major = top_major;
4034
4035 /* Set the first tab so that the top tab is near the center of the
4036 visible tabs */
4037 else
4038 {
4039 half = num_visible_major /2;
4040 half += MAX(((num_visible_major - 1) /2) - num_rest_major, 0);
4041 nb->notebook.first_major = top_major;
4042 for (i = top_major_idx - 1; i >= 0 && half > 0; i--)
4043 {
4044 child = nb->composite.children[i];
4045 nc = NotebookConstraint(child);
4046 if (nc->active && NB_IS_CHILD_MAJOR(nc->child_type))
4047 {
4048 nb->notebook.first_major = child;
4049 half--;
4050 }
4051 }
4052 }
4053 }
4054
4055 /* Minor tab */
4056 if (!(NB_IS_CHILD_MINOR(reason)))
4057 {
4058 /* Set the first tab to the starting tab in this tab section, if we
4059 do not need a page scroller or if the calculated top tab
4060 page number is less than the first page number */
4061 if (!NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller)
4062 || (top_minor_page <= nb->notebook.first_page_number))
4063 nb->notebook.first_minor = start_minor;
4064
4065 /* Set the first tab to the calculated top tab, if it is the
4066 only one that might be visible */
4067 else if (num_visible_minor <= 1)
4068 nb->notebook.first_minor = top_minor;
4069
4070 /* Set the first tab so that the top tab is near the center of the
4071 visible tabs */
4072 else
4073 {
4074 half = num_visible_minor /2;
4075 half += MAX(((num_visible_minor - 1) /2) - num_rest_minor, 0);
4076 nb->notebook.first_minor = top_minor;
4077 for (i = top_minor_idx - 1; i >= 0 && half > 0; i--)
4078 {
4079 child = nb->composite.children[i];
4080 nc = NotebookConstraint(child);
4081 if (nc->active)
4082 {
4083 if (NB_IS_CHILD_MAJOR(nc->child_type))
4084 break;
4085 else if (NB_IS_CHILD_MINOR(nc->child_type))
4086 {
4087 nb->notebook.first_minor = child;
4088 half--;
4089 }
4090 }
4091 }
4092 }
4093 }
4094 }
4095
4096
4097
4098 /*****************************************************************************
4099 * *
4100 * Drawing Functions *
4101 * *
4102 *****************************************************************************/
4103
4104
4105 /*- GetFrameGCs -------------------------------------------------------------
4106
4107 Get the GC's for drawing notebook frame and binding
4108
4109 -----------------------------------------------------------------------------*/
4110 static void
GetFrameGCs(XmNotebookWidget nb)4111 GetFrameGCs (
4112 XmNotebookWidget nb)
4113 {
4114 XGCValues values;
4115 XtGCMask mask, dynamicMask;
4116
4117 if (nb->notebook.frame_gc)
4118 XtReleaseGC((Widget)nb, nb->notebook.frame_gc);
4119 if (nb->notebook.binding_gc)
4120 XtReleaseGC((Widget)nb, nb->notebook.binding_gc);
4121
4122 dynamicMask = GCForeground;
4123 mask = GCForeground | GCBackground | GCLineWidth;
4124 values.foreground = nb->manager.foreground;
4125 values.background = nb->notebook.frame_background;
4126 values.line_width = 1;
4127 nb->notebook.frame_gc = XtAllocateGC((Widget)nb, 0, mask, &values,
4128 dynamicMask, 0);
4129
4130 mask = GCForeground | GCBackground;
4131 dynamicMask = (GCFillStyle | GCTile | GCStipple | GCTileStipXOrigin |
4132 GCTileStipYOrigin);
4133 values.foreground = nb->manager.foreground;
4134 values.background = nb->notebook.frame_background;
4135 nb->notebook.binding_gc = XtAllocateGC((Widget)nb, 0, mask, &values,
4136 dynamicMask, 0);
4137 }
4138
4139
4140 /*- GetBackpageGCs ---------------------------------------------------------
4141
4142 Get the GC's for drawing notebook backpages. These two may be
4143 shared with other widgets.
4144
4145 -----------------------------------------------------------------------------*/
4146 static void
GetBackpageGCs(XmNotebookWidget nb)4147 GetBackpageGCs (
4148 XmNotebookWidget nb)
4149 {
4150 XGCValues values;
4151 XtGCMask mask, dynamicMask, unusedMask;
4152
4153 if (nb->notebook.foreground_gc)
4154 XtReleaseGC((Widget)nb, nb->notebook.foreground_gc);
4155 if (nb->notebook.background_gc)
4156 XtReleaseGC((Widget)nb, nb->notebook.background_gc);
4157
4158 /* Will often be the same as HighlightGC in List */
4159 mask = GCForeground;
4160 dynamicMask = (GCLineWidth | GCLineStyle |
4161 GCClipMask | GCClipXOrigin | GCClipYOrigin);
4162 unusedMask = GCBackground | GCDashList;
4163 values.foreground = nb->notebook.back_page_foreground;
4164 nb->notebook.foreground_gc = XtAllocateGC((Widget)nb, 0, mask, &values,
4165 dynamicMask, unusedMask);
4166
4167 /* Will often be the same as InverseGC in List */
4168 mask |= GCGraphicsExposures;
4169 dynamicMask = GCClipMask | GCClipXOrigin | GCClipYOrigin;
4170 unusedMask = GCBackground | GCFont;
4171 values.foreground = nb->notebook.back_page_background;
4172 values.graphics_exposures = FALSE;
4173 nb->notebook.background_gc = XtAllocateGC((Widget)nb, 0, mask, &values,
4174 dynamicMask, unusedMask);
4175
4176 }
4177
4178
4179 /*- MakeSpiralPixmap -------------------------------------------------------
4180
4181 Makes a spiral binding pixmap.
4182
4183 Uses instance state:
4184 binding placement (XmNorientation and XmNbackPagePlacement)
4185
4186 Updates instance state:
4187 spiral_pixmap
4188
4189 Parameters:
4190 IN width - binding area width
4191 IN height - binding area height
4192
4193 -----------------------------------------------------------------------------*/
4194 static void
MakeSpiralPixmap(XmNotebookWidget nb,Dimension width,Dimension height)4195 MakeSpiralPixmap (
4196 XmNotebookWidget nb,
4197 Dimension width,
4198 Dimension height)
4199 {
4200 int rx=0, ry=0, rw=0, rh=0; /* rectangle values for binding surface */
4201 int sx=0, sy=0, sw=0, sh=0, sd=0; /* spiral values */
4202 int a1=0, a2=0, a3=0, a4=0; /* spiral angle values */
4203 int hx=0, hy=0, hd=0; /* hole values */
4204 int lx1=0, ly1=0, lx2=0, ly2=0; /* line values for binding edge */
4205 int pw=0, ph=0; /* pixmap size */
4206 int gap=0; /* gap between spirals */
4207 int div; /* division of binding width */
4208 int i;
4209 Pixmap pixmap;
4210
4211 /* check binding width for reasonable values */
4212 if (width < MIN_DRAWABLE_SPIRAL_SIZE || height < MIN_DRAWABLE_SPIRAL_SIZE)
4213 return;
4214
4215 /*
4216 * Determine spiral component values
4217 */
4218 if (nb->notebook.binding_pos == LEFT)
4219 {
4220 div = width / 3;
4221 gap = div / 2;
4222
4223 pw = width;
4224 ph = div + gap;
4225
4226 sx = 0;
4227 sy = gap / 2;
4228 sw = div * 2;
4229 sh = div;
4230 sd = sh / 4;
4231
4232 a1 = 270 - 20;
4233 a2 = -270;
4234 a3 = 90 - 20;
4235 a4 = 110;
4236
4237 hx = sx + sw - sd;
4238 hy = sy + (sh / 2) - sd +1;
4239 hd = MIN(div, sd * 2);
4240
4241 rx = div;
4242 ry = 0;
4243 rw = width - div;
4244 rh = ph;
4245
4246 lx1 = div;
4247 ly1 = 0;
4248 lx2 = lx1;
4249 ly2 = ph;
4250 }
4251 else if (nb->notebook.binding_pos == RIGHT)
4252 {
4253 div = width / 3;
4254 gap = div / 2;
4255
4256 pw = width;
4257 ph = div + gap;
4258
4259 sx = div - 1;
4260 sy = gap / 2;
4261 sw = div * 2;
4262 sh = div;
4263 sd = sh / 4;
4264
4265 a1 = 275;
4266 a2 = 270;
4267 a3 = 90 - 10;
4268 a4 = 100;
4269
4270 hx = sx - (sd / 2);
4271 hy = sy + (sh / 2) - sd +1;
4272 hd = MIN(div, sd * 2);
4273
4274 rx = 0;
4275 ry = 0;
4276 rw = pw - div;
4277 rh = ph;
4278
4279 lx1 = pw - div;
4280 ly1 = 0;
4281 lx2 = lx1;
4282 ly2 = rh;
4283 }
4284 else if (nb->notebook.binding_pos == TOP)
4285 {
4286 div = height / 3;
4287 gap = div / 2;
4288
4289 pw = div + gap;
4290 ph = height;
4291
4292 sx = gap / 2;
4293 sy = 0;
4294 sw = div;
4295 sh = div * 2;
4296 sd = sw / 4;
4297
4298 a1 = 0 + 15;
4299 a2 = 270;
4300 a3 = 90;
4301 a4 = 110;
4302
4303 hx = sx + (sw / 2) - sd +1;
4304 hy = sh - sd;
4305 hd = MIN(div, sd * 2);
4306
4307 rx = 0;
4308 ry = div;
4309 rw = pw;
4310 rh = height - div;
4311
4312 lx1 = 0;
4313 ly1 = div;
4314 lx2 = pw;
4315 ly2 = ly1;
4316 }
4317 else if (nb->notebook.binding_pos == BOTTOM)
4318 {
4319 div = height / 3;
4320 gap = div / 2;
4321
4322 pw = div + gap;
4323 ph = height;
4324
4325 sx = gap / 2;
4326 sy = div -1;
4327 sw = div;
4328 sh = (div * 2);
4329 sd = sw / 4;
4330
4331 a1 = 360 - 5;
4332 a2 = -295;
4333 a3 = 90 + 8;
4334 a4 = 110;
4335
4336 hx = sx + (sw / 2);
4337 hy = sy;
4338 hd = MIN(div, sd * 2);
4339
4340 rx = 0;
4341 ry = 0;
4342 rw = pw;
4343 rh = ph - div;
4344
4345 lx1 = 0;
4346 ly1 = ph - div;
4347 lx2 = pw;
4348 ly2 = ly1;
4349 }
4350
4351 /*
4352 * Create spiral pixmap, if previous one exists destroy it
4353 */
4354 if (nb->notebook.spiral_pixmap != XmUNSPECIFIED_PIXMAP
4355 && nb->notebook.spiral_pixmap != XmNONE)
4356 XFreePixmap(XtDisplay(nb), nb->notebook.spiral_pixmap);
4357
4358 pixmap = nb->notebook.spiral_pixmap =
4359 XCreatePixmap(XtDisplay(nb), XtWindow(nb), pw, ph, nb->core.depth);
4360
4361 /*
4362 * Scribble in spiral pixmap
4363 */
4364 /* Fill pixmap with notebook background */
4365 XFillRectangle(XtDisplay(nb), pixmap, nb->manager.background_GC,
4366 0, 0, pw, ph);
4367
4368 /* draw binding surface */
4369 XSetForeground(XtDisplay(nb), nb->notebook.frame_gc,
4370 nb->notebook.frame_background);
4371 XFillRectangle(XtDisplay(nb), pixmap, nb->notebook.frame_gc,
4372 rx, ry, rw, rh);
4373
4374 /* draw line along binding surface */
4375 XSetClipMask(XtDisplay(nb), nb->notebook.foreground_gc, None);
4376 XSetLineAttributes(XtDisplay(nb), nb->notebook.foreground_gc, 1,
4377 LineSolid, CapRound, JoinMiter);
4378 XDrawLine(XtDisplay(nb), pixmap, nb->notebook.foreground_gc,
4379 lx1, ly1, lx2, ly2);
4380
4381 /* draw hole in binding surface with top/bottom shadows */
4382 XFillArc(XtDisplay(nb), pixmap, nb->manager.background_GC,
4383 hx, hy, hd, hd, 0, 360 * 64);
4384 XDrawArc(XtDisplay(nb), pixmap, nb->manager.bottom_shadow_GC,
4385 hx, hy, hd, hd, 225 * 64, -180 * 64);
4386 XDrawArc(XtDisplay(nb), pixmap, nb->manager.top_shadow_GC,
4387 hx, hy, hd, hd, 45 * 64, -180 * 64);
4388
4389 /* draw spiral with top/bottom shadows */
4390 XSetForeground(XtDisplay(nb), nb->notebook.frame_gc,
4391 nb->manager.foreground);
4392 XSetLineAttributes(XtDisplay(nb), nb->notebook.frame_gc, 1,
4393 LineSolid, CapRound, JoinMiter);
4394 for(i=1; i < sd; i++)
4395 XDrawArc(XtDisplay(nb), pixmap, nb->notebook.frame_gc,
4396 sx +i, sy +i, sw -i, sh -i, a1 * 64, a2 * 64);
4397 XSetLineAttributes(XtDisplay(nb), nb->notebook.frame_gc, MAX(0,sd -2),
4398 LineSolid, CapRound, JoinMiter);
4399 XDrawArc(XtDisplay(nb), pixmap, nb->notebook.frame_gc,
4400 sx +(sd/2), sy +(sd/2), sw, sh, a3 * 64, a4 * 64);
4401 XDrawArc(XtDisplay(nb), pixmap, nb->manager.top_shadow_GC,
4402 sx, sy, sw, sh, a1 * 64, a2 * 64);
4403 XDrawArc(XtDisplay(nb), pixmap, nb->manager.bottom_shadow_GC,
4404 sx +sd, sy +sd, sw -sd, sh -sd, a1 * 64, a2 * 64);
4405 }
4406
4407
4408
4409
4410 /*- DrawBinding -------------------------------------------------------------
4411
4412 Draw the Notebook binding
4413
4414 -----------------------------------------------------------------------------*/
4415
4416 /*ARGSUSED*/
4417 static void
DrawBinding(XmNotebookWidget nb,XExposeEvent * event,Region region)4418 DrawBinding (
4419 XmNotebookWidget nb,
4420 XExposeEvent *event, /* unused */
4421 Region region)
4422 {
4423 Dimension x, y, width, height;
4424
4425 /* check binding type resource and binding width */
4426 if (nb->notebook.binding_type == XmNONE
4427 || nb->notebook.real_binding_width <= 0)
4428 return;
4429
4430 /* get the binding area */
4431 x = y = 0;
4432 if (nb->notebook.major_pos == LEFT)
4433 x += NB_MAJOR_MAX(nb, nb->notebook.major_width,
4434 nb->notebook.major_scroller_width) +
4435 nb->notebook.back_page_size + nb->notebook.frame_width;
4436 else if (nb->notebook.major_pos == TOP)
4437 y += NB_MAJOR_MAX(nb, nb->notebook.major_height,
4438 nb->notebook.major_scroller_height) +
4439 nb->notebook.back_page_size + nb->notebook.frame_height;
4440 if (nb->notebook.minor_pos == LEFT)
4441 x += NB_MINOR_MAX(nb, nb->notebook.minor_width,
4442 nb->notebook.minor_scroller_width) +
4443 nb->notebook.back_page_size;
4444 else if (nb->notebook.minor_pos == TOP)
4445 y += NB_MINOR_MAX(nb, nb->notebook.minor_height,
4446 nb->notebook.minor_scroller_height) +
4447 nb->notebook.back_page_size;
4448 if (nb->notebook.orientation == XmHORIZONTAL)
4449 {
4450 width = nb->notebook.real_binding_width;
4451 height = nb->notebook.frame_height - 1;
4452 y += 1;
4453 }
4454 else
4455 {
4456 width = nb->notebook.frame_width - 1;
4457 height = nb->notebook.real_binding_width;
4458 x += 1;
4459 }
4460
4461 /* draw the binding if applicable */
4462 if (XRectInRegion(region, x, y, width, height))
4463 {
4464 switch (nb->notebook.binding_type)
4465 {
4466 case XmSOLID:
4467 XSetForeground(XtDisplay(nb), nb->notebook.frame_gc,
4468 nb->manager.foreground);
4469 XFillRectangle(XtDisplay(nb), XtWindow(nb),
4470 nb->notebook.frame_gc, x, y, width, height);
4471 break;
4472 case XmSPIRAL:
4473 MakeSpiralPixmap (nb, width, height);
4474 DrawPixmapBinding(nb, x, y, width, height,
4475 nb->notebook.spiral_pixmap);
4476 break;
4477 case XmPIXMAP:
4478 DrawPixmapBinding(nb, x, y, width, height,
4479 nb->notebook.binding_pixmap);
4480 break;
4481 case XmPIXMAP_OVERLAP_ONLY:
4482 DrawPixmapBinding(nb, x, y, width, height,
4483 nb->notebook.binding_pixmap);
4484 break;
4485 } /* switch */
4486 } /* if */
4487 }
4488
4489
4490
4491 /*- DrawPixmapBinding -------------------------------------------------------
4492
4493 Draw the pixmap binding
4494
4495 -----------------------------------------------------------------------------*/
4496 static void
DrawPixmapBinding(XmNotebookWidget nb,Dimension x,Dimension y,Dimension width,Dimension height,Pixmap pixmap)4497 DrawPixmapBinding (
4498 XmNotebookWidget nb,
4499 Dimension x,
4500 Dimension y,
4501 Dimension width,
4502 Dimension height,
4503 Pixmap pixmap)
4504 {
4505 int depth;
4506 int x_origin, y_origin;
4507 XGCValues values;
4508 XtGCMask mask;
4509
4510 /* no pixmap? don't draw */
4511 if (pixmap == XmUNSPECIFIED_PIXMAP || pixmap == XmNONE)
4512 return;
4513
4514 /* get Pixmap depth */
4515 XmeGetPixmapData(XtScreen(nb), pixmap,
4516 NULL, &depth, NULL, NULL, NULL, NULL, NULL, NULL);
4517
4518 /* creating the gc */
4519 if (depth == 1)
4520 {
4521 mask = GCFillStyle | GCStipple;
4522 values.fill_style = FillStippled;
4523 values.stipple = pixmap;
4524 }
4525 else
4526 {
4527 mask = GCFillStyle | GCTile;
4528 values.fill_style = FillTiled;
4529 values.tile = pixmap;
4530 }
4531 XChangeGC(XtDisplay(nb), nb->notebook.binding_gc, mask, &values);
4532
4533 /*
4534 * set TSOrigin
4535 */
4536 if (nb->notebook.binding_pos == LEFT || nb->notebook.binding_pos == TOP)
4537 x_origin = x, y_origin = y;
4538 else if (nb->notebook.binding_pos == RIGHT)
4539 x_origin = x + width - 1, y_origin = y;
4540 else /* if (nb->notebook.binding_pos == BOTTOM) */
4541 x_origin = x, y_origin = y + height;
4542
4543 XSetTSOrigin(XtDisplay(nb), nb->notebook.binding_gc, x_origin, y_origin);
4544
4545 /* display the pixmap binding */
4546 XFillRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.binding_gc,
4547 x, y, width -1, height - 1);
4548 }
4549
4550
4551 /*- DrawFrameShadow ---------------------------------------------------------
4552
4553 Draw the Notebook frame shadow
4554
4555 -----------------------------------------------------------------------------*/
4556
4557 /*ARGSUSED*/
4558 static void
DrawFrameShadow(XmNotebookWidget nb,XExposeEvent * event,Region region)4559 DrawFrameShadow (
4560 XmNotebookWidget nb,
4561 XExposeEvent *event, /* unused */
4562 Region region) /* unused */
4563 {
4564 Dimension x, y, width, height;
4565 Region shadow_region;
4566 XRectangle rect;
4567
4568 /* get the page's x, y position */
4569 x = y = 1;
4570 if (nb->notebook.binding_pos == LEFT)
4571 x += nb->notebook.real_binding_width;
4572 else if (nb->notebook.binding_pos == TOP)
4573 y += nb->notebook.real_binding_width;
4574 if (nb->notebook.major_pos == LEFT)
4575 x += NB_MAJOR_MAX(nb, nb->notebook.major_width,
4576 nb->notebook.major_scroller_width) + nb->notebook.back_page_size;
4577 else if (nb->notebook.major_pos == TOP)
4578 y += NB_MAJOR_MAX(nb, nb->notebook.major_height,
4579 nb->notebook.major_scroller_height) + nb->notebook.back_page_size;
4580 if (nb->notebook.minor_pos == LEFT)
4581 x += NB_MINOR_MAX(nb, nb->notebook.minor_width,
4582 nb->notebook.minor_scroller_width) + nb->notebook.back_page_size;
4583 else if (nb->notebook.minor_pos == TOP)
4584 y += NB_MINOR_MAX(nb, nb->notebook.minor_height,
4585 nb->notebook.minor_scroller_height) + nb->notebook.back_page_size;
4586 width = nb->notebook.frame_width - 2;
4587 height = nb->notebook.frame_height - 2;
4588
4589 XSetForeground(XtDisplay(nb), nb->notebook.frame_gc,
4590 nb->notebook.frame_background);
4591
4592 /* draw the frame shadow */
4593 if (nb->notebook.shadow_thickness)
4594 {
4595 /* draw the shadow */
4596 /* creating the shadow region */
4597 shadow_region = XCreateRegion();
4598
4599 /* adding the frame area to the shadow region */
4600 rect.x = x;
4601 rect.y = y;
4602 rect.width = width;
4603 rect.height = height;
4604 XFillRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.frame_gc,
4605 x, y, width + 1, height + 1);
4606 XUnionRectWithRegion(&rect, shadow_region, shadow_region);
4607
4608 /* adding the top major tab area to the shadow region */
4609 if (nb->notebook.top_major
4610 && NB_IS_VISIBLE(nb->notebook.top_major)
4611 && !NB_IS_CHILD_JOINSIDE(nb->notebook.top_major))
4612 {
4613 rect.x = nb->notebook.top_major->core.x -
4614 nb->notebook.shadow_thickness;
4615 rect.y = nb->notebook.top_major->core.y -
4616 nb->notebook.shadow_thickness;
4617 rect.width = nb->notebook.top_major->core.width +
4618 nb->notebook.shadow_thickness * 2 - 1;
4619 rect.height = nb->notebook.top_major->core.height +
4620 nb->notebook.shadow_thickness * 2 - 1;
4621 /* ensure x/y of rect does not go negative */
4622 /* this can be removed when _XmRegionDrawShadow is fixed
4623 to allow negative y values */
4624 if( rect.x < 0)
4625 {
4626 rect.width -= rect.x;
4627 rect.x = 0;
4628 }
4629 if( rect.y < 0)
4630 {
4631 rect.height -= rect.y;
4632 rect.y = 0;
4633 }
4634
4635 XUnionRectWithRegion(&rect, shadow_region, shadow_region);
4636 }
4637
4638 /* adding the top minor tab area to the shadow region */
4639 if (nb->notebook.top_minor
4640 && NB_IS_VISIBLE(nb->notebook.top_minor)
4641 && !NB_IS_CHILD_JOINSIDE(nb->notebook.top_minor))
4642 {
4643 rect.x = nb->notebook.top_minor->core.x -
4644 nb->notebook.shadow_thickness;
4645 rect.y = nb->notebook.top_minor->core.y -
4646 nb->notebook.shadow_thickness;
4647 rect.width = nb->notebook.top_minor->core.width +
4648 nb->notebook.shadow_thickness * 2 - 1;
4649 rect.height = nb->notebook.top_minor->core.height +
4650 nb->notebook.shadow_thickness * 2 - 1;
4651 /* ensure x/y of rect does not go negative */
4652 /* this can be removed when _XmRegionDrawShadow is fixed
4653 to allow negative y values */
4654 if( rect.x < 0)
4655 {
4656 rect.width -= rect.x;
4657 rect.x = 0;
4658 }
4659 if( rect.y < 0)
4660 {
4661 rect.height -= rect.y;
4662 rect.y = 0;
4663 }
4664 XUnionRectWithRegion(&rect, shadow_region, shadow_region);
4665 }
4666
4667 /* draw the shadow */
4668 _XmRegionDrawShadow(XtDisplay(nb), XtWindow(nb),
4669 nb->manager.top_shadow_GC,
4670 nb->manager.bottom_shadow_GC,
4671 (XmRegion)shadow_region, nb->core.border_width,
4672 nb->notebook.shadow_thickness, XmSHADOW_OUT);
4673 XDestroyRegion(shadow_region);
4674 }
4675 else
4676 {
4677 XFillRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.frame_gc,
4678 x, y, width, height);
4679 XSetForeground(XtDisplay(nb), nb->notebook.frame_gc,
4680 nb->manager.foreground);
4681 XDrawRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.frame_gc,
4682 x, y, width, height);
4683 if (nb->notebook.top_major
4684 && NB_IS_VISIBLE(nb->notebook.top_major)
4685 && !NB_IS_CHILD_JOINSIDE(nb->notebook.top_major))
4686 {
4687 rect.x = nb->notebook.top_major->core.x - 1;
4688 rect.y = nb->notebook.top_major->core.y - 1;
4689 rect.width = nb->notebook.top_major->core.width + 1;
4690 rect.height = nb->notebook.top_major->core.height + 1;
4691 /* ensure x/y of rect does not go negative */
4692 /* this can be removed when _XmRegionDrawShadow is fixed
4693 to allow negative y values */
4694 if( rect.x < 0)
4695 {
4696 rect.width -= rect.x;
4697 rect.x = 0;
4698 }
4699 if( rect.y < 0)
4700 {
4701 rect.height -= rect.y;
4702 rect.y = 0;
4703 }
4704
4705 XDrawRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.frame_gc,
4706 rect.x, rect.y, rect.width, rect.height);
4707 }
4708
4709 /* adding the top minor tab area to the shadow region */
4710 if (nb->notebook.top_minor
4711 && NB_IS_VISIBLE(nb->notebook.top_minor)
4712 && !NB_IS_CHILD_JOINSIDE(nb->notebook.top_minor))
4713 {
4714 rect.x = nb->notebook.top_minor->core.x - 1;
4715 rect.y = nb->notebook.top_minor->core.y - 1;
4716 rect.width = nb->notebook.top_minor->core.width + 1;
4717 rect.height = nb->notebook.top_minor->core.height + 1;
4718 /* ensure x/y of rect does not go negative */
4719 /* this can be removed when _XmRegionDrawShadow is fixed
4720 to allow negative y values */
4721 if( rect.x < 0)
4722 {
4723 rect.width -= rect.x;
4724 rect.x = 0;
4725 }
4726 if( rect.y < 0)
4727 {
4728 rect.height -= rect.y;
4729 rect.y = 0;
4730 }
4731 XDrawRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.frame_gc,
4732 rect.x, rect.y, rect.width, rect.height);
4733 }
4734 }
4735
4736 }
4737
4738
4739 /*- DrawBackPages -----------------------------------------------------------
4740
4741 Draw Notebook back pages
4742
4743 -----------------------------------------------------------------------------*/
4744
4745 /*ARGSUSED*/
4746 static void
DrawBackPages(XmNotebookWidget nb,XExposeEvent * event,Region region)4747 DrawBackPages (
4748 XmNotebookWidget nb,
4749 XExposeEvent *event, /* unused */
4750 Region region)
4751 {
4752 int delta, back; /* backpage foreground & background deltas */
4753 int binding_width; /* the real binding width */
4754 int dx, dy; /* delta-x and delta-y */
4755 int mx, my; /* maximum delta-x and delta-y */
4756 int x, y, limit; /* temporary variables */
4757 XPoint p[5]; /* foreground line pattern */
4758 XPoint q[3]; /* background line pattern */
4759
4760
4761 /*
4762 * initialize
4763 */
4764 delta = nb->notebook.back_page_size / nb->notebook.real_back_page_number;
4765
4766 /* draw backpages on the frame, which is not necessarily along the
4767 entire binding */
4768 if (nb->notebook.binding_type == XmPIXMAP)
4769 binding_width = MAX(nb->notebook.real_binding_width,
4770 nb->notebook.binding_width);
4771 else
4772 binding_width = MIN(nb->notebook.real_binding_width,
4773 nb->notebook.binding_width);
4774
4775 /* find back page line pattern */
4776 if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT &&
4777 nb->notebook.orientation == XmHORIZONTAL)
4778 {
4779 p[1].x = nb->notebook.real_binding_width - binding_width;
4780 p[1].y = nb->notebook.frame_height;
4781 p[2].x = binding_width + nb->notebook.frame_width;
4782 p[2].y = 0;
4783 p[3].x = 0;
4784 p[3].y = - nb->notebook.frame_height;
4785 p[4].x = - delta;
4786 p[4].y = 0;
4787 p[0].x = p[1].x;
4788 p[0].y = p[1].y - delta;
4789 x = 0;
4790 y = delta;
4791 dx = dy = delta;
4792 mx = my = nb->notebook.back_page_size;
4793 }
4794 else if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT &&
4795 nb->notebook.orientation == XmVERTICAL)
4796 {
4797 p[1].x = nb->notebook.frame_width;
4798 p[1].y = nb->notebook.real_binding_width - binding_width;
4799 p[2].x = 0;
4800 p[2].y = binding_width + nb->notebook.frame_height;
4801 p[3].x = - nb->notebook.frame_width;
4802 p[3].y = 0;
4803 p[4].x = 0;
4804 p[4].y = - delta;
4805 p[0].x = p[1].x - delta;
4806 p[0].y = p[1].y;
4807 x = delta;
4808 y = 0;
4809 dx = dy = delta;
4810 mx = my = nb->notebook.back_page_size;
4811 }
4812 else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT &&
4813 nb->notebook.orientation == XmHORIZONTAL)
4814 {
4815 p[1].x = NB_MAJOR_MAX(nb, nb->notebook.major_width,
4816 nb->notebook.major_scroller_width) +
4817 nb->notebook.back_page_size + nb->notebook.frame_width +
4818 binding_width - 1;
4819 p[1].y = nb->notebook.frame_height;
4820 p[2].x = - (nb->notebook.frame_width + binding_width);
4821 p[2].y = 0;
4822 p[3].x = 0;
4823 p[3].y = - nb->notebook.frame_height;
4824 p[4].x = delta;
4825 p[4].y = 0;
4826 p[0].x = p[1].x;
4827 p[0].y = p[1].y - delta;
4828 x = 0;
4829 y = delta;
4830 dx = - delta;
4831 dy = delta;
4832 mx = - nb->notebook.back_page_size;
4833 my = nb->notebook.back_page_size;
4834 }
4835 else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT &&
4836 nb->notebook.orientation == XmVERTICAL)
4837 {
4838 p[1].x = nb->notebook.back_page_size +
4839 NB_MINOR_MAX(nb, nb->notebook.minor_width,
4840 nb->notebook.minor_scroller_width) - 1;
4841 p[1].y = nb->notebook.real_binding_width - binding_width;
4842 p[2].x = 0;
4843 p[2].y = binding_width + nb->notebook.frame_height;
4844 p[3].x = nb->notebook.frame_width;
4845 p[3].y = 0;
4846 p[4].x = 0;
4847 p[4].y = - delta;
4848 p[0].x = p[1].x + delta;
4849 p[0].y = p[1].y;
4850 x = - delta;
4851 y = 0;
4852 dx = - delta;
4853 dy = delta;
4854 mx = - nb->notebook.back_page_size;
4855 my = nb->notebook.back_page_size;
4856 }
4857 else if (nb->notebook.back_page_pos == XmTOP_RIGHT &&
4858 nb->notebook.orientation == XmHORIZONTAL)
4859 {
4860 p[1].x = nb->notebook.real_binding_width - binding_width;
4861 p[1].y = nb->notebook.back_page_size +
4862 NB_MINOR_MAX(nb, nb->notebook.minor_height,
4863 nb->notebook.minor_scroller_height) - 1;
4864 p[2].x = binding_width + nb->notebook.frame_width;
4865 p[2].y = 0;
4866 p[3].x = 0;
4867 p[3].y = nb->notebook.frame_height;
4868 p[4].x = - delta;
4869 p[4].y = 0;
4870 p[0].x = p[1].x;
4871 p[0].y = p[1].y + delta;
4872 x = 0;
4873 y = - delta;
4874 dx = delta;
4875 dy = - delta;
4876 mx = nb->notebook.back_page_size;
4877 my = - nb->notebook.back_page_size;
4878 }
4879 else if (nb->notebook.back_page_pos == XmTOP_RIGHT &&
4880 nb->notebook.orientation == XmVERTICAL)
4881 {
4882 p[1].x = nb->notebook.frame_width;
4883 p[1].y = nb->notebook.back_page_size + nb->notebook.frame_height +
4884 binding_width + NB_MAJOR_MAX(nb, nb->notebook.major_height,
4885 nb->notebook.major_scroller_height) - 1;
4886 p[2].x = 0;
4887 p[2].y = - (binding_width + nb->notebook.frame_height);
4888 p[3].x = - nb->notebook.frame_width;
4889 p[3].y = 0;
4890 p[4].x = 0;
4891 p[4].y = delta;
4892 p[0].x = p[1].x - delta;
4893 p[0].y = p[1].y;
4894 x = delta;
4895 y = 0;
4896 dx = delta;
4897 dy = - delta;
4898 mx = nb->notebook.back_page_size;
4899 my = - nb->notebook.back_page_size;
4900 }
4901 else if (nb->notebook.back_page_pos == XmTOP_LEFT &&
4902 nb->notebook.orientation == XmHORIZONTAL)
4903 {
4904 p[1].x = nb->notebook.back_page_size + nb->notebook.frame_width +
4905 binding_width + NB_MAJOR_MAX(nb, nb->notebook.major_width,
4906 nb->notebook.major_scroller_width) - 1;
4907 p[1].y = nb->notebook.back_page_size +
4908 NB_MINOR_MAX(nb, nb->notebook.minor_height,
4909 nb->notebook.minor_scroller_height) - 1;
4910 p[2].x = - (binding_width + nb->notebook.frame_width);
4911 p[2].y = 0;
4912 p[3].x = 0;
4913 p[3].y = nb->notebook.frame_height;
4914 p[4].x = delta;
4915 p[4].y = 0;
4916 p[0].x = p[1].x;
4917 p[0].y = p[1].y + delta;
4918 x = 0;
4919 y = - delta;
4920 dx = - delta;
4921 dy = - delta;
4922 mx = - nb->notebook.back_page_size;
4923 my = - nb->notebook.back_page_size;
4924 }
4925 else
4926 {
4927 p[1].x = nb->notebook.back_page_size +
4928 NB_MINOR_MAX(nb, nb->notebook.minor_width,
4929 nb->notebook.minor_scroller_width) - 1;
4930 p[1].y = nb->notebook.back_page_size + nb->notebook.frame_height +
4931 binding_width + NB_MAJOR_MAX(nb, nb->notebook.major_height,
4932 nb->notebook.major_scroller_height) -1;
4933 p[2].x = 0;
4934 p[2].y = - (binding_width + nb->notebook.frame_height);
4935 p[3].x = nb->notebook.frame_width;
4936 p[3].y = 0;
4937 p[4].x = 0;
4938 p[4].y = delta;
4939 p[0].x = p[1].x + delta;
4940 p[0].y = p[1].y;
4941 x = - delta;
4942 y = 0;
4943 dx = - delta;
4944 dy = - delta;
4945 mx = - nb->notebook.back_page_size;
4946 my = - nb->notebook.back_page_size;
4947 }
4948
4949 /* set the clipping region if necessary */
4950 XSetRegion(XtDisplay(nb), nb->notebook.foreground_gc, region);
4951 XSetRegion(XtDisplay(nb), nb->notebook.background_gc, region);
4952 XSetClipOrigin(XtDisplay(nb), nb->notebook.foreground_gc, 0, 0);
4953 XSetClipOrigin(XtDisplay(nb), nb->notebook.background_gc, 0, 0);
4954
4955 /* draw the first page outline */
4956 XSetLineAttributes(XtDisplay(nb), nb->notebook.foreground_gc, 1,
4957 LineSolid, CapButt, JoinMiter);
4958 if (nb->notebook.binding_type == XmSPIRAL ||
4959 nb->notebook.binding_type == XmPIXMAP ||
4960 nb->notebook.binding_type == XmSOLID ||
4961 nb->notebook.binding_type == XmNONE ||
4962 nb->notebook.binding_type == XmPIXMAP_OVERLAP_ONLY)
4963 {
4964 Dimension width, height;
4965 Position x, y;
4966
4967 /* We can't pass a negative width or height to the draw call.
4968 Since it appears that draw functions later in the code need
4969 the p values set as above, let's check whether the height and
4970 width here are negative and adjust the draw coordinates
4971 as appropriate. */
4972
4973 if (nb->notebook.orientation == XmHORIZONTAL)
4974 {
4975 ADJUST_NEGATIVE_DIMENSION(p[1].x, p[2].x, x, width);
4976 ADJUST_NEGATIVE_DIMENSION(p[1].y, p[3].y, y, height);
4977 XDrawRectangle(XtDisplay(nb), XtWindow(nb),
4978 nb->notebook.foreground_gc,
4979 x, y, width, height);
4980 }
4981 else
4982 {
4983 ADJUST_NEGATIVE_DIMENSION(p[1].x, p[3].x, x, width);
4984 ADJUST_NEGATIVE_DIMENSION(p[1].y, p[2].y, y, height);
4985 XDrawRectangle(XtDisplay(nb), XtWindow(nb),
4986 nb->notebook.foreground_gc,
4987 x, y, width, height);
4988 }
4989 }
4990
4991 /* for XmSOLID, XmPIXMAP, and XmPIXMAP_OVERLAP_ONLY */
4992 if (nb->notebook.binding_type == XmSOLID ||
4993 nb->notebook.binding_type == XmPIXMAP ||
4994 nb->notebook.binding_type == XmPIXMAP_OVERLAP_ONLY)
4995 {
4996 /* draw back page lines */
4997 x = p[1].x;
4998 y = p[1].y;
4999 limit = nb->notebook.back_page_size;
5000 while (limit > 0)
5001 {
5002 /* draw backpage foreground */
5003 XDrawLines(XtDisplay(nb), XtWindow(nb), nb->notebook.foreground_gc,
5004 &(p[1]), 4, CoordModePrevious);
5005
5006 /* draw backpage background */
5007 if (delta >= 2 && limit > delta - 2)
5008 {
5009 back = delta - 1;
5010 q[0].x = p[1].x;
5011 q[0].y = p[1].y;
5012 q[1].x = p[2].x;
5013 q[1].y = p[2].y;
5014 q[2].x = p[3].x;
5015 q[2].y = p[3].y;
5016 q[0].x += NB_ENFORCE_SIGN(dx, 1);
5017 q[0].y += NB_ENFORCE_SIGN(dy, 1);
5018 if (q[2].x) q[2].x += dx;
5019 if (q[2].y) q[2].y += dy;
5020 while (back > 0)
5021 {
5022 XDrawLines(XtDisplay(nb), XtWindow(nb),
5023 nb->notebook.background_gc,
5024 q, 3, CoordModePrevious);
5025 q[0].y += NB_ENFORCE_SIGN(dy, 1);
5026 q[0].x += NB_ENFORCE_SIGN(dx, 1);
5027 if (q[2].x) q[2].x -= NB_ENFORCE_SIGN(dx, 1);
5028 if (q[2].y) q[2].y -= NB_ENFORCE_SIGN(dy, 1);
5029 back--;
5030 }
5031 }
5032 p[1].x += dx;
5033 p[1].y += dy;
5034 limit -= delta;
5035 }
5036
5037 /* draw the last page line */
5038 p[0].x = x;
5039 p[0].y = y;
5040 p[1].x = mx;
5041 p[1].y = my;
5042 XSetLineAttributes(XtDisplay(nb), nb->notebook.foreground_gc, 2,
5043 LineSolid, CapButt, JoinMiter);
5044 XDrawLines(XtDisplay(nb), XtWindow(nb), nb->notebook.foreground_gc,
5045 p, 5, CoordModePrevious);
5046 }
5047
5048 /* for XmNONE and XmSPIRAL */
5049 else
5050 {
5051 /* draw back page lines */
5052 p[1].x = x;
5053 p[1].y = y;
5054 x = p[0].x;
5055 y = p[0].y;
5056 limit = nb->notebook.back_page_size;
5057 while (limit > 0)
5058 {
5059 /* draw backpage foreground */
5060 XDrawLines(XtDisplay(nb), XtWindow(nb), nb->notebook.foreground_gc,
5061 p, 5, CoordModePrevious);
5062
5063 /* draw backpage background */
5064 if (delta >= 2 && limit > delta - 2)
5065 {
5066 back = delta - 1;
5067 q[0].x = p[0].x + p[1].x;
5068 q[0].y = p[0].y + p[1].y;
5069 q[1].x = p[2].x;
5070 q[1].y = p[2].y;
5071 q[2].x = p[3].x;
5072 q[2].y = p[3].y;
5073 q[0].x += NB_ENFORCE_SIGN(dx, 1);
5074 q[0].y += NB_ENFORCE_SIGN(dy, 1);
5075 if (q[1].x)
5076 {
5077 q[0].x += dx;
5078 q[1].x -= dx;
5079 }
5080 if (q[1].y)
5081 {
5082 q[0].y += dy;
5083 q[1].y -= dy;
5084 }
5085 if (q[2].x) q[2].x += dx;
5086 if (q[2].y) q[2].y += dy;
5087 while (back > 0)
5088 {
5089 XDrawLines(XtDisplay(nb), XtWindow(nb),
5090 nb->notebook.background_gc,
5091 q, 3, CoordModePrevious);
5092 if (q[1].x)
5093 {
5094 q[0].y += NB_ENFORCE_SIGN(dy, 1);
5095 q[1].x += NB_ENFORCE_SIGN(dx, 1);
5096 }
5097 if (q[1].y)
5098 {
5099 q[0].x += NB_ENFORCE_SIGN(dx, 1);
5100 q[1].y += NB_ENFORCE_SIGN(dy, 1);
5101 }
5102 if (q[2].x) q[2].x -= NB_ENFORCE_SIGN(dx, 1);
5103 if (q[2].y) q[2].y -= NB_ENFORCE_SIGN(dy, 1);
5104 back--;
5105 }
5106 }
5107 p[0].x += dx;
5108 p[0].y += dy;
5109 limit -= delta;
5110 }
5111
5112 /* draw the last page line */
5113 p[0].x = x + mx;
5114 p[0].y = y + my;
5115 XSetLineAttributes(XtDisplay(nb), nb->notebook.foreground_gc, 2,
5116 LineSolid, CapButt, JoinMiter);
5117 XDrawLines(XtDisplay(nb), XtWindow(nb), nb->notebook.foreground_gc,
5118 p, 5, CoordModePrevious);
5119 }
5120
5121 }
5122
5123
5124
5125 /*****************************************************************************
5126 * *
5127 * Geometry Functions *
5128 * *
5129 *****************************************************************************/
5130
5131
5132 /*- CalcGeoInfo ------------------------------------------------------------
5133
5134 Calculate Notebook's preferred geometry.
5135
5136 Updates instance state:
5137 page_width
5138 page_height
5139 status_width
5140 status_height
5141 major_width
5142 major_height
5143 minor_width
5144 minor_height
5145 scroller_width
5146 scroller_height
5147 major_scroller_width
5148 major_scroller_height
5149 minor_scroller_width
5150 minor_scroller_height
5151 frame_width
5152 frame_height
5153 real_binding_width
5154 real_back_page_number, if adjust is True
5155
5156 Parameters:
5157 IN instigator - child widget requesting geo request
5158 IN desired - instigator's requested geometry
5159 IN adjust - flag to indicate whether instance geometry
5160 variables used for layout should be set.
5161 OUT preferred_width,
5162 OUT preferred_height - notebook w/h based on children sizes
5163
5164 -----------------------------------------------------------------------------*/
5165 static void
CalcGeoInfo(XmNotebookWidget nb,Widget instigator,XtWidgetGeometry * desired,Dimension * preferred_width,Dimension * preferred_height,Boolean adjust)5166 CalcGeoInfo (
5167 XmNotebookWidget nb,
5168 Widget instigator,
5169 XtWidgetGeometry *desired,
5170 Dimension *preferred_width,
5171 Dimension *preferred_height,
5172 Boolean adjust)
5173 {
5174 XmNotebookConstraint nc;
5175 Dimension width, height;
5176 Widget child;
5177 XtWidgetGeometry preferred;
5178 int i;
5179 unsigned int w, h;
5180 Dimension page_width = 0,page_height = 0;
5181 Dimension status_width = 0,status_height = 0;
5182 Dimension major_width = 0,major_height = 0;
5183 Dimension minor_width = 0,minor_height = 0;
5184 Dimension scroller_width = 0,scroller_height = 0;
5185 Dimension major_scroller_width = 0,major_scroller_height = 0;
5186 Dimension minor_scroller_width = 0,minor_scroller_height = 0;
5187 Dimension frame_width,frame_height;
5188 Dimension real_binding_width,real_back_page_number;
5189
5190 /* get width and height of children */
5191 for (i = 0; i < nb->composite.num_children; i++)
5192 {
5193 /* ask preferred size */
5194 child = nb->composite.children[i];
5195
5196 if (child == instigator)
5197 {
5198 width = IsWidth(desired)
5199 ? desired->width
5200 : XtWidth(instigator);
5201 width += (IsBorder(desired)
5202 ? desired->border_width
5203 : XtBorderWidth(instigator)) * 2;
5204 height = IsHeight(desired)
5205 ? desired->height
5206 : XtHeight(instigator);
5207 height += (IsBorder(desired)
5208 ? desired->border_width
5209 : XtBorderWidth(instigator)) * 2;
5210 }
5211 else
5212 {
5213 XtQueryGeometry(child, NULL, &preferred);
5214 width = (preferred.request_mode & CWWidth)
5215 ? preferred.width
5216 : XtWidth(child) + child->core.border_width*2;
5217 height = (preferred.request_mode & CWHeight)
5218 ? preferred.height
5219 : XtHeight(child) + child->core.border_width*2;
5220 }
5221
5222 /* get the maximum */
5223 if (XtIsManaged(child))
5224 {
5225 nc = NotebookConstraint(child);
5226 switch (nc->child_type)
5227 {
5228 case XmPAGE:
5229 ASSIGN_MAX(page_width, width);
5230 ASSIGN_MAX(page_height, height);
5231 break;
5232 case XmSTATUS_AREA:
5233 ASSIGN_MAX(status_width, width);
5234 ASSIGN_MAX(status_height, height);
5235 break;
5236 case XmMAJOR_TAB:
5237 ASSIGN_MAX(major_width, width);
5238 ASSIGN_MAX(major_height, height);
5239 break;
5240 case XmMINOR_TAB:
5241 ASSIGN_MAX(minor_width, width);
5242 ASSIGN_MAX(minor_height, height);
5243 break;
5244 case XmPAGE_SCROLLER:
5245 ASSIGN_MAX(scroller_width, width);
5246 ASSIGN_MAX(scroller_height, height);
5247 break;
5248 case XmMAJOR_TAB_SCROLLER:
5249 ASSIGN_MAX(major_scroller_width, width);
5250 ASSIGN_MAX(major_scroller_height, height);
5251 break;
5252 case XmMINOR_TAB_SCROLLER:
5253 ASSIGN_MAX(minor_scroller_width, width);
5254 ASSIGN_MAX(minor_scroller_height, height);
5255 break;
5256 }
5257 }
5258 }
5259
5260 /* adjust page's width */
5261 page_width = MAX((int)page_width, (int)(status_width + nb->notebook.margin_width +
5262 scroller_width));
5263
5264 /* set the real binding width */
5265 real_binding_width = nb->notebook.binding_width;
5266 switch (nb->notebook.binding_type)
5267 {
5268 case XmNONE:
5269 real_binding_width = 0;
5270 break;
5271 case XmSPIRAL:
5272 real_binding_width = ((int)(nb->notebook.binding_width * 3))/2;
5273 break;
5274 case XmPIXMAP:
5275 if (nb->notebook.binding_pixmap != XmUNSPECIFIED_PIXMAP
5276 && nb->notebook.binding_pixmap != XmNONE)
5277 {
5278 w = h = 0;
5279 XmeGetPixmapData(XtScreen(nb),nb->notebook.binding_pixmap,
5280 NULL,NULL,NULL,NULL,NULL,NULL,&w,&h);
5281 if (nb->notebook.orientation == XmHORIZONTAL)
5282 {
5283 ASSIGN_MAX(real_binding_width, w);
5284 }
5285 else
5286 {
5287 ASSIGN_MAX(real_binding_width, h);
5288 }
5289 }
5290 break;
5291 /* Note: in case of XmPIXMAP_OVERLAP_ONLY binding_width is used
5292 so we don't care about the Pixmap size here */
5293 }
5294
5295 /* Calculate the real back page number */
5296 real_back_page_number = nb->notebook.back_page_number;
5297 ASSIGN_MIN(real_back_page_number, (Dimension)(nb->notebook.back_page_size /2));
5298 ASSIGN_MAX(real_back_page_number, 1);
5299
5300 /* Calculate status w/h based on page,margin,& scroller w/h */
5301 status_width = MAX(0,(int)
5302 (page_width - nb->notebook.margin_width - scroller_width));
5303 status_height = scroller_height = MAX(status_height,scroller_height);
5304
5305 /* Calculate the notebook frame size based on page size,shadows,& margins*/
5306 frame_width = page_width +
5307 (nb->notebook.shadow_thickness * 2) +
5308 (nb->notebook.margin_width * 2) + 1;
5309 frame_height = page_height + status_height +
5310 (nb->notebook.shadow_thickness * 2) +
5311 (nb->notebook.margin_height * 3) + 1;
5312
5313 /*
5314 * Return calculated notebook's preferred size
5315 */
5316 /* add frame and back pages area */
5317 *preferred_width = frame_width + nb->notebook.back_page_size;
5318 *preferred_height = frame_height + nb->notebook.back_page_size;
5319
5320 /* add binding and tab area */
5321 if (nb->notebook.orientation == XmHORIZONTAL)
5322 {
5323 *preferred_width += real_binding_width +
5324 NB_MAJOR_MAX(nb, major_width, major_scroller_width);
5325 *preferred_height +=
5326 NB_MINOR_MAX(nb, minor_height, minor_scroller_height);
5327 }
5328 else
5329 {
5330 *preferred_width +=
5331 NB_MINOR_MAX(nb, minor_width, minor_scroller_width);
5332 *preferred_height += real_binding_width +
5333 NB_MAJOR_MAX(nb, major_height, major_scroller_height);
5334 }
5335
5336
5337 /*
5338 * Set notebook geometry, if adjusting
5339 */
5340 if (adjust)
5341 {
5342 nb->notebook.page_width = page_width;
5343 nb->notebook.page_height = page_height;
5344 nb->notebook.status_width = status_width;
5345 nb->notebook.status_height = status_height;
5346 nb->notebook.major_width = major_width;
5347 nb->notebook.major_height = major_height;
5348 nb->notebook.minor_width = minor_width;
5349 nb->notebook.minor_height = minor_height;
5350 nb->notebook.scroller_width = scroller_width;
5351 nb->notebook.scroller_height = scroller_height;
5352 nb->notebook.major_scroller_width = major_scroller_width;
5353 nb->notebook.major_scroller_height = major_scroller_height;
5354 nb->notebook.minor_scroller_width = minor_scroller_width;
5355 nb->notebook.minor_scroller_height = minor_scroller_height;
5356 nb->notebook.frame_width = frame_width;
5357 nb->notebook.frame_height = frame_height;
5358 nb->notebook.real_binding_width = real_binding_width;
5359 nb->notebook.real_back_page_number = real_back_page_number;
5360 }
5361 }
5362
5363
5364 /*- NewPreferredGeometry ----------------------------------------------------
5365
5366 Get Notebook's preferred geometry
5367
5368 Parameters:
5369 IN instigator - child widget requesting geo request
5370 IN desired - instigator's requested geometry
5371 OUT preferred - w/h based on child's preferred sizes
5372
5373 -----------------------------------------------------------------------------*/
5374 static Boolean
NewPreferredGeometry(XmNotebookWidget nb,Widget instigator,XtWidgetGeometry * desired,XtWidgetGeometry * preferred)5375 NewPreferredGeometry (
5376 XmNotebookWidget nb,
5377 Widget instigator,
5378 XtWidgetGeometry *desired,
5379 XtWidgetGeometry *preferred)
5380 {
5381 Dimension preferred_width, preferred_height;
5382
5383 /* calculate preferred geometry information */
5384 CalcGeoInfo(nb, instigator, desired,
5385 &preferred_width, &preferred_height, FALSE);
5386
5387 preferred->width = preferred_width;
5388 preferred->height = preferred_height;
5389 preferred->request_mode = CWHeight | CWWidth;
5390
5391 return(!((preferred->width == nb->core.width) &&
5392 (preferred->height == nb->core.height)));
5393 }
5394
5395
5396 /*- AdjustGeometry ----------------------------------------------------------
5397
5398 Adjust notebook's children sizes based on the Notebook's width
5399 and height.
5400
5401 The minimum width needed is determined by the following:
5402 1. page and status are minimized until they reach XmNbackPageWidth
5403 2. binding is minimized
5404 3. major tabs are minimized
5405 4. page scroller is minimized
5406 5. back pages and frame are clipped
5407
5408 The minimum height needed is determined by the following:
5409 1. page is minimized
5410 2. status and page scroller are minimized
5411 3. minor tabs are minimized
5412 4. back pages and frame are clipped
5413
5414 -----------------------------------------------------------------------------*/
5415 static void
AdjustGeometry(XmNotebookWidget nb,Widget instigator,XtWidgetGeometry * desired)5416 AdjustGeometry (
5417 XmNotebookWidget nb,
5418 Widget instigator,
5419 XtWidgetGeometry *desired)
5420 {
5421 Dimension ideal_width,ideal_height;
5422
5423 /* the value min is the minimum width/height that the Notebook can be
5424 after a component is reduced to its minimum */
5425 Dimension min;
5426
5427 /* calculate preferred geometry information */
5428 CalcGeoInfo(nb, instigator, desired, &ideal_width, &ideal_height, TRUE);
5429
5430 /* adjust children's width */
5431 /* Notebook's width is bigger than ideal width */
5432 if (nb->core.width > ideal_width)
5433 nb->notebook.page_width += nb->core.width - ideal_width;
5434
5435 /* Notebook's width is smaller than ideal width */
5436 else if (nb->core.width < ideal_width)
5437 {
5438 /* minimize the page area */
5439 min = ideal_width - nb->notebook.page_width +
5440 nb->notebook.scroller_width;
5441 if (nb->core.width >= min)
5442 nb->notebook.page_width = nb->core.width -
5443 (min - nb->notebook.scroller_width);
5444 else if (nb->core.width < min)
5445 {
5446 nb->notebook.page_width = nb->notebook.scroller_width;
5447 if (nb->notebook.orientation == XmHORIZONTAL)
5448 {
5449 /* minimize the binding area */
5450 min -= nb->notebook.real_binding_width;
5451 if (nb->core.width >= min)
5452 nb->notebook.real_binding_width = nb->core.width - min;
5453 else
5454 {
5455 /* minimize major tabs */
5456 nb->notebook.real_binding_width = 0;
5457 min -= nb->notebook.major_width;
5458 if (nb->core.width > min)
5459 nb->notebook.major_width = nb->core.width - min;
5460 else
5461 nb->notebook.major_width = 0;
5462 }
5463 }
5464 else
5465 {
5466 /* minimize minor tabs */
5467 min -= nb->notebook.minor_width;
5468 if (nb->core.width > min)
5469 nb->notebook.minor_width = nb->core.width - min;
5470 else
5471 nb->notebook.minor_width = 0;
5472 }
5473 }
5474 }
5475
5476 /* adjust children's height */
5477 /* Notebook's height is bigger than ideal height */
5478 if (nb->core.height > ideal_height)
5479 nb->notebook.page_height += nb->core.height - ideal_height;
5480
5481 /* Notebook's height is smaller than ideal height */
5482 else if (nb->core.height < ideal_height)
5483 {
5484 /* minimize the page area */
5485 min = ideal_height - nb->notebook.page_height;
5486 if (nb->core.height >= min)
5487 nb->notebook.page_height = nb->core.height - min;
5488 else if (nb->core.height < min)
5489 {
5490 /* minimize the page scroller area */
5491 nb->notebook.page_height = 0;
5492 min -= nb->notebook.scroller_height;
5493 if (nb->core.height >= min)
5494 nb->notebook.scroller_height = nb->notebook.status_height =
5495 nb->core.height - min;
5496 else
5497 {
5498 nb->notebook.scroller_height = nb->notebook.status_height = 0;
5499 if (nb->notebook.orientation == XmVERTICAL)
5500 {
5501 /* minimize the binding area */
5502 min -= nb->notebook.real_binding_width;
5503 if (nb->core.height >= min)
5504 nb->notebook.real_binding_width = nb->core.height - min;
5505 else
5506 {
5507 /* minimize major tabs */
5508 nb->notebook.real_binding_width = 0;
5509 min -= nb->notebook.major_height;
5510 if (nb->core.height > min)
5511 nb->notebook.major_height = nb->core.height - min;
5512 else
5513 nb->notebook.major_height = 0;
5514 }
5515 }
5516 else
5517 {
5518 /* minimize minor tabs */
5519 min -= nb->notebook.minor_height;
5520 if (nb->core.height > min)
5521 nb->notebook.minor_height = nb->core.height - min;
5522 else
5523 nb->notebook.minor_height = 0;
5524 }
5525 }
5526 }
5527 }
5528
5529 /* Calculate status w/h based on page,margin,& scroller w/h */
5530 nb->notebook.status_width = MAX(0,(int)(nb->notebook.page_width -
5531 nb->notebook.margin_width - nb->notebook.scroller_width));
5532 nb->notebook.status_height = nb->notebook.scroller_height =
5533 MAX(nb->notebook.status_height, nb->notebook.scroller_height);
5534
5535 /* Calculate the notebook frame size based on page size,shadows,& margins*/
5536 nb->notebook.frame_width = nb->notebook.page_width +
5537 (nb->notebook.shadow_thickness * 2) +
5538 (nb->notebook.margin_width * 2) + 1;
5539 nb->notebook.frame_height = nb->notebook.page_height + nb->notebook.status_height +
5540 (nb->notebook.shadow_thickness * 2) +
5541 (nb->notebook.margin_height * 3) + 1;
5542
5543 }
5544
5545
5546
5547 /*****************************************************************************
5548 * *
5549 * Child Managing Functions *
5550 * *
5551 *****************************************************************************/
5552
5553
5554 /*- SetLastPageNumber ----------------------------------------------------
5555
5556 Sets XmNlastPageNumber if no explicit last page number was set,
5557 and updates navigators.
5558
5559 Uses instance state:
5560 dynamic_last_page_num ,True, if no explicit setting
5561
5562 Called from:
5563 AssignDefaultPageNumber ,when children are managed
5564 ConstraintSetValues ,when a child page # is changed
5565
5566 Return:
5567 True, if last_page_number changed. Otherwise, False.
5568
5569 -----------------------------------------------------------------------------*/
5570 static Boolean
SetLastPageNumber(XmNotebookWidget nb,int last_page_number)5571 SetLastPageNumber (
5572 XmNotebookWidget nb,
5573 int last_page_number)
5574 {
5575 if (nb->notebook.dynamic_last_page_num
5576 && last_page_number > nb->notebook.last_page_number)
5577 {
5578 nb->notebook.last_page_number = last_page_number;
5579 UpdateNavigators(nb);
5580 return(True);
5581 }
5582 return(False);
5583 }
5584
5585
5586 /*- AssignDefaultPageNumber -------------------------------------------------
5587
5588 assign a default page number to those children who did not get
5589 from the application.
5590
5591 When a page is managed without a page number, the Notebook provides
5592 the page with the smallest unallocated page number that is greater
5593 than or equal to the first page number and is greater than the last
5594 allocated page number. When a tab or a status area is managed without
5595 a page number, the widget gets the page number of the most recently
5596 managed page that does not have the same type of child. If the page
5597 does have the same type of child, however, the Notebook associates the
5598 child with the next page whose page number is one greater than the
5599 most recently managed one. The Notebook, then, assumes the new page
5600 number is occupied. The next subsequent page without a page number
5601 will not receive this number. The default page number that the Notebook
5602 generates can exceed the last page number, which makes those page
5603 inaccessable by the user.
5604
5605 -----------------------------------------------------------------------------*/
5606 static Boolean
AssignDefaultPageNumber(XmNotebookWidget nb)5607 AssignDefaultPageNumber (
5608 XmNotebookWidget nb)
5609 {
5610 XmNotebookConstraint nc;
5611 Widget child;
5612 int i, last_page_number;
5613
5614 /* initialize */
5615 last_page_number = nb->notebook.first_page_number;
5616
5617 /* for all children */
5618 for (i = 0; i < nb->composite.num_children; i++)
5619 {
5620 child = nb->composite.children[i];
5621 nc = NotebookConstraint(child);
5622
5623 /* for all managed children */
5624 if (XtIsManaged(child))
5625 {
5626 /* assign a default page number */
5627 if (nc->page_number == XmUNSPECIFIED_PAGE_NUMBER)
5628 {
5629 if (NB_IS_CHILD_PAGE(nc->child_type))
5630 {
5631 nc->page_number = GetNextAvailPageNum(nb, i);
5632 nb->notebook.last_alloc_num = nc->page_number;
5633 }
5634 else if (NB_IS_CHILD_MAJOR(nc->child_type) ||
5635 NB_IS_CHILD_MINOR(nc->child_type) ||
5636 NB_IS_CHILD_STATUS(nc->child_type))
5637 {
5638 if (GetChildWidget(nb, nb->notebook.last_alloc_num,
5639 nc->child_type))
5640 {
5641 nc->page_number = GetNextAvailPageNum(nb, i);
5642 nb->notebook.last_alloc_num = nc->page_number;
5643 }
5644 else
5645 nc->page_number = nb->notebook.last_alloc_num;
5646 }
5647 }
5648 else
5649 nb->notebook.last_alloc_num = nc->page_number;
5650
5651 /* update the last_page_number */
5652 if (NB_IS_CHILD_PAGE(nc->child_type)
5653 || NB_IS_CHILD_TAB(nc->child_type)
5654 || NB_IS_CHILD_STATUS(nc->child_type))
5655 {
5656 ASSIGN_MAX(last_page_number, nc->page_number);
5657 }
5658 } /* if */
5659 } /* for */
5660 return(SetLastPageNumber(nb, last_page_number));
5661 }
5662
5663
5664 /*- SetActiveChildren ------------------------------------------------------
5665
5666 Determine which children should be active.
5667
5668 Active children are all managed scrollers and managed pages, status
5669 areas, and tabs which are within the page number range and not
5670 duplicated or later matched ones if duplicated.
5671
5672 Uses instance state:
5673 first_page_number
5674 last_page_number
5675
5676 Updates child constraint "active" field
5677 FALSE, if child is NOT managed or
5678 child page # less than notebook.first_page_number or
5679 child page # greater than notebook.last_page_number or
5680 child page # duplicated by a child of the same type
5681 TRUE, otherwise
5682
5683
5684 -----------------------------------------------------------------------------*/
5685 static void
SetActiveChildren(XmNotebookWidget nb)5686 SetActiveChildren (
5687 XmNotebookWidget nb)
5688 {
5689 Widget child;
5690 XmNotebookConstraint nc;
5691 XmNotebookConstraint last = NULL; /* initial previous child */
5692 unsigned char type = XmNONE; /* initial previous type */
5693 int num = XmUNSPECIFIED_PAGE_NUMBER; /* initial previous page */
5694 int i;
5695
5696 for (i = 0; i < nb->composite.num_children; i++)
5697 {
5698 child = nb->composite.children[i];
5699 nc = NotebookConstraint(child);
5700 if (XtIsManaged(child)
5701 && nc->page_number >= nb->notebook.first_page_number
5702 && nc->page_number <= nb->notebook.last_page_number)
5703 {
5704 if (last)
5705 last->active = !(nc->child_type == type
5706 && nc->page_number == num);
5707 last = nc;
5708 type = nc->child_type;
5709 num = nc->page_number;
5710 }
5711 else /* NOT managed or NOT (1st page) <= (page #) <= (last page #) */
5712 {
5713 nc->active = False;
5714 }
5715 }
5716 if (last)
5717 last->active = True;
5718 }
5719
5720
5721 /*- CompareChildren ---------------------------------------------------------
5722
5723 Compares children, used for qsort() in SortChildren.
5724
5725 -----------------------------------------------------------------------------*/
5726 static int
CompareChildren(XmConst void * a,XmConst void * b)5727 CompareChildren (
5728 XmConst void *a,
5729 XmConst void *b)
5730 {
5731 XmNotebookConstraint ac = NotebookConstraint(*((Widget *)a));
5732 XmNotebookConstraint bc = NotebookConstraint(*((Widget *)b));
5733 int cmp;
5734
5735 /* Compare page numbers */
5736 cmp = ac->page_number - bc->page_number;
5737
5738 /* Compare child types, if page numbers are same */
5739 if (!cmp)
5740 cmp = ac->child_type - bc->child_type;
5741
5742 /* Compare position in the array, if child types are the same */
5743 if (!cmp)
5744 cmp = (unsigned long)a - (unsigned long)b;
5745
5746 return cmp;
5747 }
5748
5749
5750 /*- SortChildren ------------------------------------------------------------
5751
5752 Sorts children by page number and type.
5753
5754 Assumptions:
5755 Previously created children are already sorted,
5756 and newly created children are at the end of the
5757 composite.children list.
5758
5759 -----------------------------------------------------------------------------*/
5760 static void
SortChildren(XmNotebookWidget nb)5761 SortChildren (
5762 XmNotebookWidget nb)
5763 {
5764
5765
5766 qsort(nb->composite.children, nb->composite.num_children,
5767 sizeof(Widget), CompareChildren);
5768
5769 SetActiveChildren(nb);
5770 }
5771
5772
5773 /*- RepositionChild ---------------------------------------------------------
5774
5775 Repositions a childs position in composite array using an
5776 insertion method.
5777
5778 -----------------------------------------------------------------------------*/
5779 static void
RepositionChild(XmNotebookWidget nb,Widget child)5780 RepositionChild (
5781 XmNotebookWidget nb,
5782 Widget child)
5783 {
5784 XmNotebookConstraint rnc = NotebookConstraint(child);
5785 XmNotebookConstraint nc; /* temp comparator value */
5786 Widget w; /* temp comparator value */
5787 int cmp; /* temp comparator value */
5788 int cur_pos = -1; /* position of changing child */
5789 int ins_pos = -1; /* position to insert child */
5790 int i; /* counter */
5791
5792 /* nothing to do, if there is only one child in array */
5793 if (nb->composite.num_children == 1)
5794 return;
5795
5796 for (i = 0; i < nb->composite.num_children; i++)
5797 {
5798 w = nb->composite.children[i];
5799 nc = NotebookConstraint(w);
5800 if (rnc == nc)
5801 cur_pos = i;
5802 else if (ins_pos < 0)
5803 {
5804 cmp = rnc->page_number - nc->page_number;
5805 if (!cmp) cmp = rnc->child_type - nc->child_type;
5806 if (!cmp) cmp = (unsigned long)child - (unsigned long)w;
5807 if (cmp < 0)
5808 ins_pos = i; /* should be inserted before this element */
5809 }
5810 } /* for */
5811
5812 /* error, unable to locate repositioning child in array??? */
5813 if (cur_pos < 0)
5814 return;
5815
5816 /* found no one less than, move others down, and insert at last position */
5817 if (ins_pos < 0)
5818 {
5819 for (i = cur_pos; i < nb->composite.num_children -1; i++)
5820 nb->composite.children[i] = nb->composite.children[i+1];
5821 nb->composite.children[nb->composite.num_children -1] = child;
5822 }
5823 /* found new position above, move others down, and then insert */
5824 else if (cur_pos < ins_pos)
5825 {
5826 for (i = cur_pos; i < ins_pos -1; i++)
5827 nb->composite.children[i] = nb->composite.children[i+1];
5828 nb->composite.children[ins_pos -1] = child;
5829 }
5830 /* found new position below, move others up, and then insert */
5831 else if (cur_pos > ins_pos)
5832 {
5833 for (i = cur_pos; i > ins_pos; i--)
5834 nb->composite.children[i] = nb->composite.children[i-1];
5835 nb->composite.children[ins_pos] = child;
5836 }
5837 }
5838
5839
5840 /*- GetNextAvailPageNum -----------------------------------------------------
5841
5842 Finds out the next available page number for allocating it to
5843 a newly created page or other child.
5844
5845 -----------------------------------------------------------------------------*/
5846 static int
GetNextAvailPageNum(XmNotebookWidget nb,int last)5847 GetNextAvailPageNum(
5848 XmNotebookWidget nb,
5849 int last)
5850 {
5851 XmNotebookConstraint nc;
5852 Widget child;
5853 int i, avail;
5854
5855 avail = nb->notebook.last_alloc_num;
5856 for (i = 0; i < last; i++)
5857 {
5858 child = nb->composite.children[i];
5859 nc = NotebookConstraint(child);
5860 if (XtIsManaged(child) && nc->page_number == avail)
5861 avail++;
5862 }
5863 return avail;
5864 }
5865
5866
5867 /*- GetChildWidget ---------------------------------------------------------
5868
5869 Finds the later matched child widget of the specified type.
5870 It returns NULL if not found.
5871
5872 -----------------------------------------------------------------------------*/
5873 static Widget
GetChildWidget(XmNotebookWidget nb,int page_number,unsigned char child_type)5874 GetChildWidget(
5875 XmNotebookWidget nb,
5876 int page_number,
5877 unsigned char child_type)
5878 {
5879 XmNotebookConstraint nc;
5880 Widget child, this_w;
5881 int i;
5882
5883 this_w = NULL;
5884 for (i = 0; i < nb->composite.num_children; i++)
5885 {
5886 child = nb->composite.children[i];
5887 nc = NotebookConstraint(child);
5888 if (nc->page_number == page_number && nc->child_type == child_type)
5889 {
5890 this_w = child;
5891 }
5892 else
5893 {
5894 /* Skip remaining array once last matching child is found */
5895 if (this_w)
5896 break;
5897 }
5898 }
5899 return this_w;
5900 }
5901
5902
5903 /*- GotoPage ---------------------------------------------------------------
5904
5905 Places the specified page on top.
5906
5907 If the specified page IS currently on top nothing is done.
5908 Otherwise,
5909 - the XmNpageChangedCallback is called. During which
5910 notebook.in_callback is set to True. This is checked
5911 in XmNotebook:ConstraintSetValues() to avoid performing
5912 layout at that time.
5913 - navigators are updated
5914 - relayout is performed
5915
5916 Called from:
5917 SetValues(), when notebook.current_page_number is set
5918 TabPressed(), when tabs are activated
5919 PageMove(), when ScrollFrame trait navigation is triggered
5920
5921 -----------------------------------------------------------------------------*/
5922 static void
GotoPage(XmNotebookWidget nb,int page_number,XEvent * event,int reason)5923 GotoPage(
5924 XmNotebookWidget nb,
5925 int page_number,
5926 XEvent *event,
5927 int reason)
5928 {
5929 XmNotebookCallbackStruct call_value;
5930 Dimension save_width, save_height;
5931 Widget old_top_major, old_first_major;
5932 Widget old_top_minor, old_first_minor;
5933 int prev_page = nb->notebook.current_page_number;
5934
5935
5936 /* Don't bother when the page number is out of the page number
5937 range, or if it is same as the old page number */
5938 if ( page_number == nb->notebook.current_page_number
5939 || page_number < nb->notebook.first_page_number
5940 || page_number > nb->notebook.last_page_number)
5941 return;
5942
5943 /* Save the notebook's size before invoking the callback */
5944 save_width = XtWidth(nb);
5945 save_height = XtHeight(nb);
5946
5947 /* Set the NEW current page number */
5948 nb->notebook.current_page_number = page_number;
5949
5950 /* Invoke the XmNpageChangedCallback, if any exist */
5951 if ((XtHasCallbacks((Widget)nb, XmNpageChangedCallback)
5952 == XtCallbackHasSome))
5953 {
5954 call_value.reason = reason;
5955 call_value.event = event;
5956 call_value.page_number = page_number;
5957 call_value.page_widget = GetChildWidget(nb, page_number, XmPAGE);
5958 call_value.prev_page_number = prev_page;
5959 call_value.prev_page_widget = GetChildWidget(nb, prev_page, XmPAGE);
5960
5961 /* Mark that the callback is being called and when it finishes */
5962 nb->notebook.in_callback = True;
5963 XtCallCallbackList((Widget)nb, nb->notebook.page_change_callback,
5964 &call_value);
5965 nb->notebook.in_callback = False;
5966 }
5967
5968 /* Tell all navigators about our page change */
5969 UpdateNavigators(nb);
5970
5971 /* If there is any visual change caused by the callback then
5972 relayout and redisplay children */
5973 if (save_width != XtWidth(nb) || save_height != XtHeight(nb))
5974 {
5975 LayoutChildren(nb, NULL);
5976 if (XtIsRealized((Widget)nb))
5977 XClearArea(XtDisplay(nb),XtWindow(nb),0,0,0,0,True);
5978 }
5979 /* Otherwise just relayout children */
5980 else
5981 {
5982 /* Save top tab pointers */
5983 old_top_major = nb->notebook.top_major;
5984 old_first_major = nb->notebook.first_major;
5985 old_top_minor = nb->notebook.top_minor;
5986 old_first_minor = nb->notebook.first_minor;
5987
5988 /* Reset tab pointers */
5989 ResetTopPointers(nb, XmPAGE, 0);
5990
5991 /* Layout children */
5992 LayoutPages(nb, NULL);
5993
5994 if ( old_top_major != nb->notebook.top_major
5995 || old_first_major != nb->notebook.first_major)
5996 LayoutMajorTabs(nb, NULL);
5997
5998 if ( old_top_minor != nb->notebook.top_minor
5999 || old_first_minor != nb->notebook.first_minor)
6000 LayoutMinorTabs(nb, NULL);
6001 }
6002
6003
6004 }
6005
6006
6007
6008 /*****************************************************************************
6009 * *
6010 * utility functions *
6011 * *
6012 *****************************************************************************/
6013
6014
6015 /*- ShowChild ---------------------------------------------------------------
6016
6017 Change the dimensional aspects of a child, and display it.
6018
6019 -----------------------------------------------------------------------------*/
6020 static void
ShowChild(Widget child,Widget instigator,int x,int y,int width,int height)6021 ShowChild (
6022 Widget child,
6023 Widget instigator,
6024 int x,
6025 int y,
6026 int width,
6027 int height)
6028 {
6029 int border_width;
6030
6031 /* adjust width and height and calculate border_width */
6032 border_width = child->core.border_width;
6033 width -= border_width * 2;
6034 height -= border_width * 2;
6035 /* Since width and height can potentially be 0, need to check
6036 that they aren't negative after subtracting the border */
6037 if (width <= 0)
6038 width = 1, border_width = 0;
6039 if (height <= 0)
6040 height = 1, border_width = 0;
6041
6042 /* Configure the object */
6043 if (child == instigator)
6044 {
6045 /* if this child is making a geometry request */
6046 XtX(child) = x;
6047 XtY(child) = y;
6048 XtWidth(child) = width;
6049 XtHeight(child) = height;
6050 }
6051 else
6052 {
6053 /* otherwise, configure the child */
6054 XmeConfigureObject(child,
6055 (Position)x,
6056 (Position)y,
6057 (Dimension)width,
6058 (Dimension)height,
6059 (Dimension)border_width);
6060 }
6061 }
6062
6063
6064 /*- HideChild ---------------------------------------------------------------
6065
6066 Hide a child by placing it to invisible place.
6067
6068 -----------------------------------------------------------------------------*/
6069 static void
HideChild(Widget child,Widget instigator)6070 HideChild (
6071 Widget child,
6072 Widget instigator)
6073 {
6074 int x = - (int)(child->core.width + child->core.border_width * 2);
6075 int y = - (int)(child->core.height + child->core.border_width * 2);
6076
6077 /* if the child is already invisible, don't bother */
6078 if (!NB_IS_VISIBLE(child))
6079 return;
6080
6081 /* place the child to (x, y) */
6082 if (child == instigator)
6083 {
6084 /* if child is making a geometry request */
6085 XtX(child) = (Position)x;
6086 XtY(child) = (Position)y;
6087 }
6088 else
6089 {
6090 /* otherwise, configure the child */
6091 XmeConfigureObject(child,
6092 (Position)x,
6093 (Position)y,
6094 child->core.width,
6095 child->core.height,
6096 child->core.border_width);
6097 }
6098 }
6099
6100
6101 /*- HideShadowedTab ---------------------------------------------------------
6102
6103 Clear tab child and its surrounding frame shadow
6104
6105 -----------------------------------------------------------------------------*/
6106 static void
HideShadowedTab(XmNotebookWidget nb,Widget child)6107 HideShadowedTab (
6108 XmNotebookWidget nb,
6109 Widget child)
6110 {
6111 int x, y, width, height;
6112
6113 if (XtIsRealized((Widget)nb) && child && NB_IS_VISIBLE(child))
6114 {
6115 x = child->core.x - nb->notebook.shadow_thickness;
6116 y = child->core.y - nb->notebook.shadow_thickness;
6117 width = child->core.width + nb->notebook.shadow_thickness * 2 + 1;
6118 height = child->core.height + nb->notebook.shadow_thickness * 2 + 1;
6119 if ( nb->notebook.shadow_thickness )
6120 XClearArea(XtDisplay(nb), XtWindow(nb), x, y, width, height, True);
6121 else
6122 XClearArea(XtDisplay(nb), XtWindow(nb), x - 1 , y - 1, width + 1, height + 1, True);
6123 }
6124 }
6125
6126
6127
6128 /*****************************************************************************
6129 * *
6130 * callback functions *
6131 * *
6132 *****************************************************************************/
6133
6134
6135 /*- FlipTabs ----------------------------------------------------------------
6136
6137 callback function for events for tab scrolling
6138
6139 -----------------------------------------------------------------------------*/
6140
6141 /*ARGSUSED*/
6142 static void
FlipTabs(Widget w,XtPointer data,XtPointer call_data)6143 FlipTabs (
6144 Widget w,
6145 XtPointer data, /* unused */
6146 XtPointer call_data) /* unused */
6147 {
6148 XmNotebookWidget nb = (XmNotebookWidget)XtParent(w);
6149 Widget old_first_major, old_first_minor;
6150 Widget cfw = XmGetFocusWidget((Widget)nb);
6151
6152 /* save tab pointers */
6153 old_first_major = nb->notebook.first_major;
6154 old_first_minor = nb->notebook.first_minor;
6155
6156 /* request to reset notebook.first_major */
6157 if (w == nb->notebook.next_major)
6158 ResetTopPointers(nb, XmMAJOR_TAB_SCROLLER, _NEXT);
6159 else if (w == nb->notebook.prev_major)
6160 ResetTopPointers(nb, XmMAJOR_TAB_SCROLLER, _PREVIOUS);
6161 else if (w == nb->notebook.next_minor)
6162 ResetTopPointers(nb, XmMINOR_TAB_SCROLLER, _NEXT);
6163 else if (w == nb->notebook.prev_minor)
6164 ResetTopPointers(nb, XmMINOR_TAB_SCROLLER, _PREVIOUS);
6165
6166 /* redraw tabs if necessary */
6167 if (old_first_major != nb->notebook.first_major)
6168 LayoutMajorTabs(nb, NULL);
6169 if (old_first_minor != nb->notebook.first_minor)
6170 LayoutMinorTabs(nb, NULL);
6171
6172 /*
6173 * If focus was a tab widget that is now hidden due to tab scrolling then
6174 * move focus to the next visible tab
6175 */
6176 if (cfw && XtParent(cfw) == (Widget)nb)
6177 {
6178 unsigned char ct = NotebookConstraint(cfw)->child_type;
6179
6180 if (NB_IS_HIDDEN(cfw) && NB_IS_CHILD_TAB(ct))
6181 {
6182 if ((w == nb->notebook.next_major) && NB_IS_CHILD_MAJOR(ct))
6183 XmProcessTraversal(
6184 (Widget) GetNextTab(nb, XmMAJOR_TAB, 0, _FIRST_VISIBLE),
6185 XmTRAVERSE_CURRENT);
6186 else if (w == nb->notebook.prev_major && NB_IS_CHILD_MAJOR(ct))
6187 XmProcessTraversal(
6188 (Widget) GetNextTab(nb, XmMAJOR_TAB, 0, _LAST_VISIBLE),
6189 XmTRAVERSE_CURRENT);
6190 else if (w == nb->notebook.next_minor && NB_IS_CHILD_MINOR(ct))
6191 XmProcessTraversal(
6192 (Widget) GetNextTab(nb, XmMINOR_TAB, 0, _FIRST_VISIBLE),
6193 XmTRAVERSE_CURRENT);
6194 else if (w == nb->notebook.prev_minor && NB_IS_CHILD_MINOR(ct))
6195 XmProcessTraversal(
6196 (Widget) GetNextTab(nb, XmMINOR_TAB, 0, _LAST_VISIBLE),
6197 XmTRAVERSE_CURRENT);
6198 }
6199 }
6200 }
6201
6202
6203 /*- TabPressed --------------------------------------------------------------
6204
6205 callback function for events for tab push-buttons.
6206
6207 -----------------------------------------------------------------------------*/
6208 static void
TabPressed(Widget w,XtPointer data,XtPointer call_data)6209 TabPressed (
6210 Widget w,
6211 XtPointer data,
6212 XtPointer call_data)
6213 {
6214 XmNotebookWidget nb = (XmNotebookWidget)XtParent(w);
6215 XmNotebookConstraint nc = NotebookConstraint(w);
6216 XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *)call_data;
6217 int reason = (unsigned long)data;
6218
6219 /* move to the selected page */
6220 GotoPage(nb, nc->page_number, cbs->event, reason);
6221 }
6222
6223
6224
6225 /*****************************************************************************
6226 * *
6227 * Keyboard Traversal Functions & Action Procs *
6228 * *
6229 *****************************************************************************/
6230
6231
6232 /*- TraverseTab -------------------------------------------------------------
6233
6234 action for moving the focus on tabs
6235
6236 -----------------------------------------------------------------------------*/
6237
6238 /*ARGSUSED*/
6239 static void
TraverseTab(Widget w,XEvent * event,String * params,Cardinal * num_params)6240 TraverseTab (
6241 Widget w,
6242 XEvent *event, /* unused */
6243 String *params,
6244 Cardinal *num_params)
6245 {
6246 XmNotebookWidget nb = (XmNotebookWidget)w;
6247 XmNotebookConstraint nc;
6248 Widget first, last, next, prev, child = NULL;
6249 int traverse_to;
6250
6251 /* Check error conditions */
6252 if (nb && XmIsNotebook(nb))
6253 child = XmGetFocusWidget(w);
6254 else
6255 while (nb && !(XmIsNotebook(nb)))
6256 {
6257 child = (Widget)nb;
6258 nb = (XmNotebookWidget)XtParent(child);
6259 }
6260 if (!nb || !child)
6261 return;
6262
6263 if (!num_params || (*num_params != 1) || !params)
6264 {
6265 XmeWarning(w, MESSAGE1);
6266 return;
6267 }
6268
6269 /* Only valid for major or minor tabs */
6270 if (!(nc = NotebookConstraint(child))
6271 || !(NB_IS_CHILD_MAJOR(nc->child_type)
6272 || NB_IS_CHILD_MINOR(nc->child_type)))
6273 return;
6274
6275 if (_XmConvertActionParamToRepTypeId((Widget) nb,
6276 XmRID_NOTEBOOK_TRAVERSE_TAB_ACTION_PARAMS,
6277 params[0], False, &traverse_to) == False)
6278 traverse_to = _HOME;
6279
6280
6281 /*
6282 * Make the traversal
6283 */
6284 if (traverse_to == _HOME)
6285 {
6286 /* Major HOME traversal */
6287 first = GetNextTab(nb,nc->child_type,nc->page_number,_HOME);
6288 if ((first) && NB_IS_HIDDEN(first))
6289 {
6290 if (NB_IS_CHILD_MAJOR(nc->child_type))
6291 {
6292 ResetTopPointers(nb,XmMAJOR_TAB_SCROLLER,_HOME);
6293 LayoutMajorTabs(nb, NULL);
6294 }
6295 else
6296 {
6297 ResetTopPointers(nb,XmMINOR_TAB_SCROLLER,_HOME);
6298 LayoutMinorTabs(nb, NULL);
6299 }
6300 }
6301 if (first)
6302 XmProcessTraversal(first,XmTRAVERSE_CURRENT);
6303 }
6304
6305 else if (traverse_to == _END)
6306 {
6307 last = GetNextTab(nb,nc->child_type,nc->page_number,_END);
6308 if ((last) && NB_IS_HIDDEN(last))
6309 {
6310 if (NB_IS_CHILD_MAJOR(nc->child_type))
6311 {
6312 ResetTopPointers(nb,XmMAJOR_TAB_SCROLLER,_END);
6313 LayoutMajorTabs(nb, NULL);
6314 }
6315 else
6316 {
6317 ResetTopPointers(nb,XmMINOR_TAB_SCROLLER,_END);
6318 LayoutMinorTabs(nb, NULL);
6319 }
6320 }
6321 if (last)
6322 XmProcessTraversal(last,XmTRAVERSE_CURRENT);
6323 }
6324
6325 else if (traverse_to == _PREVIOUS)
6326 {
6327 prev = GetNextTab(nb,nc->child_type,nc->page_number,_PREVIOUS);
6328 if ((prev) && NB_IS_HIDDEN(prev))
6329 {
6330 if (NB_IS_CHILD_MAJOR(nc->child_type))
6331 FlipTabs(
6332 (MaxIsRightUp(nb,nc->child_type)) ?
6333 nb->notebook.prev_major : nb->notebook.next_major,
6334 NULL,NULL);
6335 else
6336 FlipTabs(
6337 (MaxIsRightUp(nb,nc->child_type)) ?
6338 nb->notebook.prev_minor : nb->notebook.next_minor,
6339 NULL,NULL);
6340 }
6341 if (prev)
6342 XmProcessTraversal(prev, XmTRAVERSE_CURRENT);
6343 }
6344
6345 else if (traverse_to == _NEXT)
6346 {
6347 next = GetNextTab(nb,nc->child_type,nc->page_number,_NEXT);
6348 if ((next) && NB_IS_HIDDEN(next))
6349 {
6350 if (NB_IS_CHILD_MAJOR(nc->child_type))
6351 FlipTabs(
6352 (MaxIsRightUp(nb,nc->child_type)) ?
6353 nb->notebook.next_major : nb->notebook.prev_major,
6354 NULL,NULL);
6355 else
6356 FlipTabs(
6357 (MaxIsRightUp(nb,nc->child_type)) ?
6358 nb->notebook.next_minor : nb->notebook.prev_minor,
6359 NULL,NULL);
6360 }
6361 if (next)
6362 XmProcessTraversal(next, XmTRAVERSE_CURRENT);
6363 }
6364 }
6365
6366
6367 /*- RedirectTraversal -------------------------------------------------------
6368
6369 redirect traversal control trait
6370
6371 Focus From Focus To Focus Request
6372 NEXT_TAB_GROUP <anything> MINOR _CURRENT_VISIBLE MAJOR
6373 MAJOR <anything> _CURRENT_VISIBLE MINOR
6374 PREV_TAB_GROUP <anything> MAJOR _CURRENT_VISIBLE MINOR
6375 MINOR <anything> _CURRENT_VISIBLE MAJOR
6376
6377
6378 -----------------------------------------------------------------------------*/
6379
6380 /*ARGSUSED*/
6381 static Widget
RedirectTraversal(Widget old_focus,Widget new_focus,unsigned int focus_policy,XmTraversalDirection direction,unsigned int pass)6382 RedirectTraversal(
6383 Widget old_focus,
6384 Widget new_focus,
6385 unsigned int focus_policy,
6386 XmTraversalDirection direction,
6387 unsigned int pass) /* unused */
6388 {
6389 unsigned char to_type = XmMAJOR_TAB, from_type = XmMAJOR_TAB;
6390 Widget to_child, from_child;
6391 Widget to_parent, from_parent;
6392 Widget new_focus_widget;
6393
6394 /* If we're in pointer focus mode there's nothing to be done. */
6395 if ((focus_policy != XmEXPLICIT)
6396 || ((direction != XmTRAVERSE_NEXT_TAB_GROUP) &&
6397 (direction != XmTRAVERSE_PREV_TAB_GROUP)))
6398 return new_focus;
6399
6400 /* Determine nearest notebook parent for the target. */
6401 to_parent = NULL;
6402 if ((to_child=new_focus))
6403 {
6404 if ((to_parent=XtParent(to_child)) == NULL)
6405 return new_focus;
6406 while (!XmIsNotebook(to_parent))
6407 {
6408 to_child = to_parent;
6409 if ((to_parent=XtParent(to_child)) == NULL)
6410 break;
6411 }
6412 }
6413
6414 /* Determine target child type. */
6415 if (to_parent)
6416 to_type = NotebookConstraint(to_child)->child_type;
6417
6418 /* Determine nearest notebook parent for the source. */
6419 from_parent = NULL;
6420 if ((from_child=old_focus))
6421 {
6422 if ((from_parent = XtParent(from_child)) == NULL)
6423 return new_focus;
6424 while (!XmIsNotebook(from_parent))
6425 {
6426 from_child = from_parent;
6427 if ((from_parent=XtParent(from_child)) == NULL)
6428 break;
6429 }
6430 }
6431
6432 /* Determine source child type. */
6433 if (from_parent)
6434 from_type = NotebookConstraint(from_child)->child_type;
6435
6436 /*
6437 * Determine if we need to force traversal between major and
6438 * minor tabs (traverse to nearest tab to the current page)
6439 *
6440 * Note: If TO is NULL, then it is assumed that there is only
6441 * one TAB GROUP i.e., the Major/Minor tabs TAB GROUP
6442 */
6443 new_focus_widget = NULL;
6444
6445 if (direction == XmTRAVERSE_NEXT_TAB_GROUP)
6446 {
6447 /* If FROM Minor with a NULL TO then GOTO Major */
6448 if (to_child == NULL && (from_parent && (from_type == XmMINOR_TAB)))
6449 new_focus_widget = GetNextTab((XmNotebookWidget)from_parent,
6450 XmMAJOR_TAB,0,_CURRENT_VISIBLE);
6451
6452 /* If FROM Major with any TO then GOTO Minor */
6453 else if (from_parent && (from_type == XmMAJOR_TAB))
6454 new_focus_widget = GetNextTab((XmNotebookWidget)from_parent,
6455 XmMINOR_TAB,0,_CURRENT_VISIBLE);
6456
6457 /* If *NOT* FROM Major and TO Minor then GOTO Major */
6458 else if (to_parent && (to_type == XmMINOR_TAB))
6459 new_focus_widget = GetNextTab((XmNotebookWidget)to_parent,
6460 XmMAJOR_TAB,0,_CURRENT_VISIBLE);
6461
6462 /* If TO Major with any FROM then GOTO Major */
6463 else if (to_parent && (to_type == XmMAJOR_TAB))
6464 new_focus_widget = GetNextTab((XmNotebookWidget)to_parent,
6465 XmMAJOR_TAB,0,_CURRENT_VISIBLE);
6466 }
6467 else /* if (direction == XmTRAVERSE_PREV_TAB_GROUP) */
6468 {
6469 /* If FROM Major with a NULL TO then GOTO Minor */
6470 if (to_child == NULL && (from_parent && (from_type == XmMAJOR_TAB)))
6471 new_focus_widget = GetNextTab((XmNotebookWidget)from_parent,
6472 XmMINOR_TAB,0,_CURRENT_VISIBLE);
6473
6474 /* If FROM Minor with any TO and then GOTO Major */
6475 else if (from_parent && (from_type == XmMINOR_TAB))
6476 new_focus_widget = GetNextTab((XmNotebookWidget)from_parent,
6477 XmMAJOR_TAB,0,_CURRENT_VISIBLE);
6478
6479 /* If *NOT* FROM Minor with TO Major then GOTO Major */
6480 else if (to_parent && (to_type == XmMAJOR_TAB))
6481 new_focus_widget = GetNextTab((XmNotebookWidget)to_parent,
6482 XmMINOR_TAB,0,_CURRENT_VISIBLE);
6483
6484 /* If to a Minor then traverse to a Minor nearest the current page */
6485 else if (to_parent && (to_type == XmMINOR_TAB))
6486 new_focus_widget = GetNextTab((XmNotebookWidget)to_parent,
6487 XmMINOR_TAB,0,_CURRENT_VISIBLE);
6488 }
6489
6490 if (new_focus_widget && XmIsTraversable(new_focus_widget))
6491 return new_focus_widget;
6492
6493 return new_focus;
6494 }
6495
6496 /*- GetNextTab --------------------------------------------------------------
6497
6498 Get next tab to set focus to.
6499
6500 In Parameters:
6501 child_type XmMAJOR_TAB or XmMINOR_TAB
6502 page_number page number of interest
6503 direction traversal direction
6504 returns
6505 next major || minor tab (can be NULL)
6506
6507 -----------------------------------------------------------------------------*/
6508 static Widget
GetNextTab(XmNotebookWidget nb,unsigned char child_type,int page_number,unsigned char direction)6509 GetNextTab (
6510 XmNotebookWidget nb,
6511 unsigned char child_type,
6512 int page_number,
6513 unsigned char direction)
6514 {
6515 XmNotebookConstraint nc;
6516 Widget child;
6517 int i;
6518 Widget target;
6519 unsigned char target_dir;
6520 unsigned char target_child_type;
6521 Boolean target_found;
6522 int top_major_page;
6523
6524 if (NB_IS_CHILD_MAJOR(child_type) || NB_IS_CHILD_MINOR(child_type))
6525 target_child_type = child_type;
6526 else
6527 return(NULL); /* Bad parameter */
6528
6529 if (MaxIsRightUp(nb,target_child_type))
6530 target_dir = direction;
6531 else
6532 switch(direction)
6533 {
6534 case _PREVIOUS:
6535 target_dir = _NEXT;
6536 break;
6537 case _NEXT:
6538 target_dir = _PREVIOUS;
6539 break;
6540 default:
6541 target_dir = direction;
6542 }
6543
6544 /*
6545 * Attempt to return top tab
6546 */
6547 if (target_dir == _CURRENT_VISIBLE)
6548 {
6549 if (NB_IS_CHILD_MAJOR(child_type))
6550 {
6551 if ( (nb->notebook.top_major != NULL)
6552 && (NB_IS_VISIBLE(nb->notebook.top_major)))
6553 return nb->notebook.top_major;
6554 else
6555 target_dir = _FIRST_VISIBLE;
6556 }
6557 else if (NB_IS_CHILD_MINOR(child_type))
6558 {
6559 if ( (nb->notebook.top_minor != NULL)
6560 && (NB_IS_VISIBLE(nb->notebook.top_minor)))
6561 return nb->notebook.top_minor;
6562 else
6563 target_dir = _FIRST_VISIBLE;
6564 }
6565 }
6566
6567 i = 0;
6568 target = NULL;
6569 target_found = False;
6570 if (NB_IS_CHILD_MAJOR(target_child_type))
6571 {
6572 while((!target_found) && (i < nb->composite.num_children))
6573 {
6574 child = nb->composite.children[i];
6575 nc = NotebookConstraint(child);
6576 if ((nc->active) && (NB_IS_CHILD_MAJOR(nc->child_type)))
6577 switch (target_dir)
6578 {
6579 case _HOME:
6580 target = child;
6581 target_found = True;
6582 break;
6583 case _FIRST_VISIBLE:
6584 if (NB_IS_VISIBLE(child))
6585 {
6586 target = child;
6587 target_found = True;
6588 }
6589 break;
6590 case _LAST_VISIBLE:
6591 if (NB_IS_VISIBLE(child))
6592 {
6593 target = child;
6594 }
6595 break;
6596 case _PREVIOUS:
6597 if (nc->page_number < page_number)
6598 target = child;
6599 else
6600 target_found = True;
6601 break;
6602 case _NEXT:
6603 if (nc->page_number > page_number)
6604 {
6605 target = child;
6606 target_found = True;
6607 }
6608 break;
6609 case _END:
6610 target = child;
6611 } /* switch */
6612 i++;
6613 } /* while */
6614 } /* if */
6615 else /* NB_IS_CHILD_MINOR(target_child_type) */
6616 {
6617 top_major_page = nb->notebook.top_major ?
6618 NotebookConstraint(nb->notebook.top_major)->page_number :
6619 nb->notebook.first_page_number - 1;
6620
6621 while((!target_found) && (i < nb->composite.num_children))
6622 {
6623 child = nb->composite.children[i];
6624 nc = NotebookConstraint(child);
6625 if (NB_IS_CHILD_MAJOR(nc->child_type)
6626 && (nc->page_number > top_major_page))
6627 target_found = True;
6628 else
6629 if ((nc->active)
6630 && (NB_IS_CHILD_MINOR(nc->child_type))
6631 && (nc->page_number >= top_major_page))
6632 switch (target_dir)
6633 {
6634 case _HOME:
6635 target = child;
6636 target_found = True;
6637 break;
6638 case _FIRST_VISIBLE:
6639 if (NB_IS_VISIBLE(child))
6640 {
6641 target = child;
6642 target_found = True;
6643 }
6644 break;
6645 case _LAST_VISIBLE:
6646 if (NB_IS_VISIBLE(child))
6647 {
6648 target = child;
6649 }
6650 break;
6651 case _PREVIOUS:
6652 if (nc->page_number < page_number)
6653 target = child;
6654 else
6655 target_found = True;
6656 break;
6657 case _NEXT:
6658 if (nc->page_number > page_number)
6659 {
6660 target = child;
6661 target_found = True;
6662 }
6663 break;
6664 case _END:
6665 target = child;
6666 } /* switch */
6667 i++;
6668 } /* while */
6669 } /* else */
6670 return(target);
6671 }
6672
6673
6674 /*- MaxIsRightUp ------------------------------------------------------------
6675
6676 returns
6677 True,
6678 if "<Key>osfRight" and "<Key>osfDown" mean "next"
6679 and "<Key>osfLeft" and "<Key>osfUp" mean "prev"
6680
6681 False,
6682 if "<Key>osfLeft" and "<Key>osfUp" mean "next"
6683 and "<Key>osfRight" and "<Key>osfDown" mean "prev"
6684
6685 -----------------------------------------------------------------------------*/
6686 static Boolean
MaxIsRightUp(XmNotebookWidget nb,unsigned char child_type)6687 MaxIsRightUp (
6688 XmNotebookWidget nb,
6689 unsigned char child_type)
6690 {
6691 return( (
6692 (NB_IS_CHILD_MAJOR(child_type))
6693 && (
6694 (nb->notebook.back_page_pos == XmBOTTOM_RIGHT)
6695 || (
6696 (nb->notebook.back_page_pos == XmBOTTOM_LEFT)
6697 && (nb->notebook.orientation == XmHORIZONTAL))
6698 ||
6699 (
6700 (nb->notebook.back_page_pos == XmTOP_RIGHT)
6701 && (nb->notebook.orientation == XmVERTICAL))))
6702 || (
6703 (NB_IS_CHILD_MINOR(child_type))
6704 && (
6705 (nb->notebook.back_page_pos == XmBOTTOM_RIGHT)
6706 || (
6707 (nb->notebook.back_page_pos == XmBOTTOM_LEFT)
6708 && (nb->notebook.orientation == XmVERTICAL))
6709 || (
6710 (nb->notebook.back_page_pos == XmTOP_RIGHT)
6711 && (nb->notebook.orientation == XmHORIZONTAL)))));
6712 }
6713
6714
6715
6716 /*****************************************************************************
6717 * *
6718 * Trait Stuff *
6719 * *
6720 *****************************************************************************/
6721
6722
6723 /*- ScrollFrameInit ---------------------------------------------------------
6724
6725 ScrollFrame init trait method
6726
6727 -----------------------------------------------------------------------------*/
6728 static void
ScrollFrameInit(Widget w,XtCallbackProc moveCB,Widget scrollable)6729 ScrollFrameInit (
6730 Widget w,
6731 XtCallbackProc moveCB,
6732 Widget scrollable)
6733 {
6734 XmNotebookWidget nb = (XmNotebookWidget)w;
6735
6736 if (nb->notebook.scroll_frame_data != NULL)
6737 return;
6738
6739 nb->notebook.scroll_frame_data = (XmScrollFrameData)
6740 XtMalloc(sizeof(XmScrollFrameDataRec));
6741
6742 nb->notebook.scroll_frame_data->num_nav_list = 0 ;
6743 nb->notebook.scroll_frame_data->nav_list = NULL ;
6744 nb->notebook.scroll_frame_data->num_nav_slots = 0 ;
6745
6746 nb->notebook.scroll_frame_data->move_cb = moveCB ;
6747 nb->notebook.scroll_frame_data->scrollable = scrollable ;
6748 }
6749
6750
6751 /*- ScrollFrameGetInfo ------------------------------------------------------
6752
6753 ScrollFrame getInfo trait method
6754 Notebook is a 1 dimensional frame.
6755
6756 -----------------------------------------------------------------------------*/
6757 static Boolean
ScrollFrameGetInfo(Widget w,Cardinal * dimension,Widget ** nav_list,Cardinal * num_nav_list)6758 ScrollFrameGetInfo (
6759 Widget w,
6760 Cardinal *dimension,
6761 Widget **nav_list,
6762 Cardinal *num_nav_list)
6763 {
6764 XmNotebookWidget nb = (XmNotebookWidget)w;
6765
6766 if (dimension) *dimension = 1; /* one dimensional frame */
6767
6768 if (nb->notebook.scroll_frame_data != NULL)
6769 {
6770 if (nav_list)
6771 *nav_list = nb->notebook.scroll_frame_data->nav_list;
6772 if (num_nav_list)
6773 *num_nav_list = nb->notebook.scroll_frame_data->num_nav_list;
6774 }
6775
6776 return( nb->notebook.scroll_frame_data != NULL );
6777 }
6778
6779
6780 /*- AddNavigator ------------------------------------------------------------
6781
6782 ScrollFrame addNavigator trait method
6783
6784 -----------------------------------------------------------------------------*/
6785 static void
AddNavigator(Widget w,Widget nav,Mask dimMask)6786 AddNavigator (
6787 Widget w,
6788 Widget nav,
6789 Mask dimMask)
6790 {
6791 XmNotebookWidget nb = (XmNotebookWidget)w;
6792 if (nb->notebook.scroll_frame_data != NULL)
6793 _XmSFAddNavigator(w, nav, dimMask, nb->notebook.scroll_frame_data);
6794 }
6795
6796
6797 /*- RemoveNavigator ---------------------------------------------------------
6798
6799 ScrollFrame removeNavigator trait method
6800
6801 -----------------------------------------------------------------------------*/
6802 static void
RemoveNavigator(Widget w,Widget nav)6803 RemoveNavigator (
6804 Widget w,
6805 Widget nav)
6806 {
6807 XmNotebookWidget nb = (XmNotebookWidget)w;
6808
6809 if (nb->notebook.scroll_frame_data != NULL)
6810 _XmSFRemoveNavigator(w, nav, nb->notebook.scroll_frame_data);
6811 }
6812
6813
6814 /*- PageMove ----------------------------------------------------------------
6815
6816 Callback for the value changes of navigators.
6817
6818 -----------------------------------------------------------------------------*/
6819
6820 /*ARGSUSED*/
6821 static void
PageMove(Widget w,XtPointer data,XtPointer call_data)6822 PageMove (
6823 Widget w,
6824 XtPointer data,
6825 XtPointer call_data) /* unused */
6826 {
6827 /* w is a navigator widget */
6828 XmNotebookWidget nb = (XmNotebookWidget)data;
6829 XmNavigatorDataRec nav_data;
6830 XmNavigatorTrait navigatorT;
6831 int reason;
6832
6833 /* Get the new navigator value using the trait getValue */
6834 nav_data.valueMask = NavValue;
6835
6836 /* Check to ensure navigator is ok */
6837 if ((navigatorT=NB_NAVIGATOR(w)) == NULL || navigatorT->getValue == NULL)
6838 return;
6839 navigatorT->getValue(w, &nav_data);
6840
6841 /* Determine the callback reason */
6842 if (nav_data.value.x > nb->notebook.current_page_number)
6843 reason = XmCR_PAGE_SCROLLER_INCREMENT;
6844 else if (nav_data.value.x < nb->notebook.current_page_number)
6845 reason = XmCR_PAGE_SCROLLER_DECREMENT;
6846 else
6847 reason = XmCR_NONE;
6848
6849 /* Look at the kind of navigator and make the appropriate move */
6850 if ((nav_data.dimMask & NavigDimensionX) && (reason != XmCR_NONE))
6851 GotoPage(nb, nav_data.value.x, NULL, reason);
6852
6853 }
6854
6855
6856 /*- UpdateNavigators --------------------------------------------------------
6857
6858 Update navigators due to page change
6859
6860 -----------------------------------------------------------------------------*/
6861 static void
UpdateNavigators(XmNotebookWidget nb)6862 UpdateNavigators (
6863 XmNotebookWidget nb)
6864 {
6865 XmNavigatorDataRec nav_data;
6866
6867 /* update navigators */
6868 nav_data.value.x = nb->notebook.current_page_number;
6869 nav_data.minimum.x = nb->notebook.first_page_number;
6870 nav_data.maximum.x = nb->notebook.last_page_number + 1;
6871 nav_data.slider_size.x = 1;
6872 nav_data.increment.x = 1;
6873 nav_data.page_increment.x = 1;
6874 nav_data.dimMask = NavigDimensionX;
6875 nav_data.valueMask = NavValue | NavMinimum | NavMaximum |
6876 NavSliderSize | NavIncrement | NavPageIncrement;
6877
6878 _XmSFUpdateNavigatorsValue((Widget)nb, &nav_data, True);
6879
6880 /* Control arrow sensitivity if using default page scroller */
6881 if (nb->notebook.scroller_status == DEFAULT_USED)
6882 {
6883 if ((nb->notebook.current_page_number ==nb->notebook.last_page_number)
6884 && (nb->notebook.current_page_number ==nb->notebook.first_page_number))
6885 XtVaSetValues(nb->notebook.scroller_child,XmNarrowSensitivity,
6886 XmARROWS_INSENSITIVE, NULL);
6887 else if (nb->notebook.current_page_number ==
6888 nb->notebook.last_page_number)
6889 XtVaSetValues(nb->notebook.scroller_child,XmNarrowSensitivity,
6890 XmARROWS_DECREMENT_SENSITIVE, NULL);
6891 else if (nb->notebook.current_page_number ==
6892 nb->notebook.first_page_number)
6893 XtVaSetValues(nb->notebook.scroller_child,XmNarrowSensitivity,
6894 XmARROWS_INCREMENT_SENSITIVE, NULL);
6895 else
6896 XtVaSetValues(nb->notebook.scroller_child,XmNarrowSensitivity,
6897 XmARROWS_SENSITIVE, NULL);
6898 }
6899 }
6900
6901
6902 /*- GetUnhighlightGC --------------------------------------------------------
6903
6904 ScrollFrame removeNavigator trait method
6905
6906 -----------------------------------------------------------------------------*/
6907 static GC
GetUnhighlightGC(Widget w,Widget child)6908 GetUnhighlightGC (
6909 Widget w,
6910 Widget child)
6911 {
6912 XmNotebookWidget nb = (XmNotebookWidget)w;
6913 XmNotebookConstraint nc;
6914 GC background_GC = NULL;
6915
6916 if (child)
6917 {
6918 nc = NotebookConstraint(child);
6919 switch (nc->child_type)
6920 {
6921 case XmMAJOR_TAB:
6922 if (nb->notebook.top_major == child)
6923 {
6924 XSetForeground(XtDisplay(nb), nb->notebook.frame_gc,
6925 nb->notebook.frame_background);
6926 background_GC = nb->notebook.frame_gc;
6927 }
6928 else
6929 background_GC = nb->manager.background_GC;
6930 break;
6931
6932 case XmMINOR_TAB:
6933 if (nb->notebook.top_minor == child)
6934 {
6935 XSetForeground(XtDisplay(nb), nb->notebook.frame_gc,
6936 nb->notebook.frame_background);
6937 background_GC = nb->notebook.frame_gc;
6938 }
6939 else
6940 background_GC = nb->manager.background_GC;
6941 break;
6942
6943 case XmPAGE:
6944 case XmPAGE_SCROLLER:
6945 case XmSTATUS_AREA:
6946 XSetForeground(XtDisplay(nb), nb->notebook.frame_gc,
6947 nb->notebook.frame_background);
6948 background_GC = nb->notebook.frame_gc;
6949 break;
6950
6951 case XmMAJOR_TAB_SCROLLER:
6952 case XmMINOR_TAB_SCROLLER:
6953 background_GC = nb->manager.background_GC;
6954 break;
6955
6956 }
6957 }
6958
6959 return(background_GC);
6960 }
6961
6962
6963
6964 /*****************************************************************************
6965 * *
6966 * Public Functions *
6967 * *
6968 *****************************************************************************/
6969
6970
6971 XmNotebookPageStatus
XmNotebookGetPageInfo(Widget notebook,int page_number,XmNotebookPageInfo * page_info)6972 XmNotebookGetPageInfo (
6973 Widget notebook,
6974 int page_number,
6975 XmNotebookPageInfo *page_info)
6976 {
6977 XmNotebookWidget nb = (XmNotebookWidget)notebook;
6978 XmNotebookConstraint nc;
6979 Widget child;
6980 Widget page, status, major_tab, minor_tab;
6981 XmNotebookPageStatus result;
6982 int i;
6983 _XmWidgetToAppContext(notebook);
6984
6985 _XmAppLock(app);
6986
6987 /* initialize */
6988 page = status = major_tab = minor_tab = NULL;
6989 result = XmPAGE_EMPTY;
6990
6991 /* searching for the page */
6992 for (i = 0; i < nb->composite.num_children; i++)
6993 {
6994 child = nb->composite.children[i];
6995 nc = NotebookConstraint(child);
6996
6997 if (nc->page_number > page_number)
6998 break;
6999 switch (nc->child_type)
7000 {
7001 case XmPAGE:
7002 if (nc->page_number == page_number)
7003 {
7004 if (nc->active)
7005 {
7006 page = child;
7007 if (result == XmPAGE_EMPTY)
7008 result = XmPAGE_FOUND;
7009 }
7010 else
7011 result = XmPAGE_DUPLICATED;
7012 }
7013 break;
7014 case XmSTATUS_AREA:
7015 if ((nc->active) && (nc->page_number == page_number))
7016 status = child;
7017 break;
7018 case XmMAJOR_TAB:
7019 if (nc->active)
7020 major_tab = child;
7021 break;
7022 case XmMINOR_TAB:
7023 if (nc->active)
7024 minor_tab = child;
7025 break;
7026 }
7027 }
7028
7029 /* see if the page number is invalid */
7030 if (page_number < nb->notebook.first_page_number ||
7031 page_number > nb->notebook.last_page_number)
7032 result = XmPAGE_INVALID;
7033
7034 /* fill the XmNotebookPageInfo struct */
7035 page_info->page_number = page_number;
7036 page_info->page_widget = page;
7037 page_info->status_area_widget = status;
7038 page_info->major_tab_widget = major_tab;
7039 page_info->minor_tab_widget = minor_tab;
7040
7041 _XmAppUnlock(app);
7042 return result;
7043 }
7044
7045
7046 Widget
XmCreateNotebook(Widget parent,String name,ArgList arglist,Cardinal argcount)7047 XmCreateNotebook(
7048 Widget parent,
7049 String name,
7050 ArgList arglist,
7051 Cardinal argcount)
7052 {
7053 /*
7054 * Create an instance of a notebook and return the widget id.
7055 */
7056 return(XtCreateWidget(name,xmNotebookWidgetClass,parent,arglist,argcount));
7057 }
7058
7059 Widget
XmVaCreateNotebook(Widget parent,char * name,...)7060 XmVaCreateNotebook(
7061 Widget parent,
7062 char *name,
7063 ...)
7064 {
7065 register Widget w;
7066 va_list var;
7067 int count;
7068
7069 Va_start(var,name);
7070 count = XmeCountVaListSimple(var);
7071 va_end(var);
7072
7073
7074 Va_start(var, name);
7075 w = XmeVLCreateWidget(name,
7076 xmNotebookWidgetClass,
7077 parent, False,
7078 var, count);
7079 va_end(var);
7080 return w;
7081 }
7082
7083 Widget
XmVaCreateManagedNotebook(Widget parent,char * name,...)7084 XmVaCreateManagedNotebook(
7085 Widget parent,
7086 char *name,
7087 ...)
7088 {
7089 Widget w = NULL;
7090 va_list var;
7091 int count;
7092
7093 Va_start(var, name);
7094 count = XmeCountVaListSimple(var);
7095 va_end(var);
7096
7097 Va_start(var, name);
7098 w = XmeVLCreateWidget(name,
7099 xmNotebookWidgetClass,
7100 parent, True,
7101 var, count);
7102 va_end(var);
7103 return w;
7104 }
7105
7106 /* End of Notebook.c */
7107
7108