2
* Copyright(c) 1992 Bell Communications Research, Inc. (Bellcore)
3
* Copyright(c) 1995-99 Andrew Lister
6
* Permission to use, copy, modify and distribute this material for
7
* any purpose and without fee is hereby granted, provided that the
8
* above copyright notice and this permission notice appear in all
9
* copies, and that the name of Bellcore not be used in advertising
10
* or publicity pertaining to this material without the specific,
11
* prior written permission of an authorized representative of
14
* BELLCORE MAKES NO REPRESENTATIONS AND EXTENDS NO WARRANTIES, EX-
15
* PRESS OR IMPLIED, WITH RESPECT TO THE SOFTWARE, INCLUDING, BUT
16
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17
* FITNESS FOR ANY PARTICULAR PURPOSE, AND THE WARRANTY AGAINST IN-
18
* FRINGEMENT OF PATENTS OR OTHER INTELLECTUAL PROPERTY RIGHTS. THE
19
* SOFTWARE IS PROVIDED "AS IS", AND IN NO EVENT SHALL BELLCORE OR
20
* ANY OF ITS AFFILIATES BE LIABLE FOR ANY DAMAGES, INCLUDING ANY
21
* LOST PROFITS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES RELAT-
22
* ING TO THE SOFTWARE.
24
* $Id: Actions.c,v 1.1 1999/09/11 01:25:36 fnevgeny Exp $
28
* Actions.c created by Andrew Lister (7 August, 1995)
40
#include <Xm/ScrollBar.h>
41
#include <Xbae/MatrixP.h>
42
#include <Xbae/Clip.h>
43
#include <Xbae/Draw.h>
44
#include <Xbae/Actions.h>
45
#include <Xbae/Utils.h>
46
#include <Xbae/ScrollMgr.h>
47
#include <Xbae/ClipP.h>
48
#include <X11/cursorfont.h>
50
#ifndef XlibSpecificationRelease
51
#define XrmPermStringToQuark XrmStringToQuark
54
#if !defined(DRAW_RESIZE_LINE) && !defined(DRAW_RESIZE_SHADOW)
55
/* One of DRAW_RESIZE_LINE and DRAW_RESIZE_SHADOW must be defined. */
56
#define DRAW_RESIZE_SHADOW
59
#ifndef DEFAULT_SCROLL_SPEED
60
#define DEFAULT_SCROLL_SPEED 500
75
} XbaeMatrixResizeColumnStruct;
83
} XbaeMatrixButtonPressedStruct;
90
XtAppContext app_context;
91
unsigned long interval;
98
} XbaeMatrixScrollStruct;
100
static int DoubleClick P((XbaeMatrixWidget, XEvent *, int, int));
101
static void DrawSlideColumn P((XbaeMatrixWidget, int));
102
static void SlideColumn P((Widget, XtPointer, XEvent *, Boolean *));
103
static void PushButton P((Widget, XtPointer, XEvent *, Boolean *));
104
static void updateScroll P((XtPointer));
105
static void checkScrollValues P((Widget, XtPointer, XEvent *, Boolean *));
106
static void callSelectCellAction P((XbaeMatrixWidget, XEvent *));
108
static int last_row = 0;
109
static int last_column = 0;
111
static int last_selected_row = 0;
112
static int last_selected_column = 0;
114
static Boolean scrolling = False;
118
xbaeDefaultActionACT(w, event, params, nparams)
130
* Get Matrix widget and make sure it is a Matrix subclass.
131
* w could be Matrix, or the Clip or textField children of Matrix
133
if (XtIsSubclass(w, xbaeMatrixWidgetClass))
134
mw = (XbaeMatrixWidget)w;
135
else if (XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass))
136
mw = (XbaeMatrixWidget)XtParent(w);
139
XtWidgetToApplicationContext(w),
140
"defaultActionACT", "badWidget", "XbaeMatrix",
141
"XbaeMatrix: Bad widget passed to DefaultAction action",
146
if (!mw->matrix.default_action_callback)
149
if (!xbaeEventToXY(mw, event, &x, &y, &cell))
152
if (!xbaeXYToRowCol(mw, &x, &y, &row, &column, cell))
155
if (DoubleClick(mw, event, row, column))
157
XbaeMatrixDefaultActionCallbackStruct call_data;
159
call_data.reason = XbaeDefaultActionReason;
160
call_data.event = event;
162
call_data.column = column;
164
XtCallCallbackList((Widget)mw, mw->matrix.default_action_callback,
165
(XtPointer)&call_data);
171
DrawSlideColumn(mw, x)
175
#ifdef DRAW_RESIZE_SHADOW
176
/* These values derived through that age-old process
177
* of what looks good to me */
178
#define SHADOW_WIDTH 2
179
#define RESIZE_COLUMN_LINE_WIDTH 4
180
Dimension width = RESIZE_COLUMN_LINE_WIDTH;
181
Dimension shadow_width = SHADOW_WIDTH;
185
Display *display = XtDisplay(mw);
186
int column = xbaeXtoCol(mw, x - COLUMN_LABEL_OFFSET(mw));
190
#ifdef DRAW_RESIZE_LINE
191
GC gc = mw->matrix.draw_gc;
193
Boolean need_vert_dead_space_fill = NEED_VERT_DEAD_SPACE_FILL(mw);
194
unsigned int clip_reason;
197
* If the column being resized is a fixed one then we don't need to
198
* bother with the clip region
200
if (column < (int)mw->matrix.fixed_columns)
202
y = ROW_LABEL_OFFSET(mw);
203
height = VISIBLE_HEIGHT(mw) + FIXED_ROW_HEIGHT(mw) +
204
TRAILING_FIXED_ROW_HEIGHT(mw);
207
if (need_vert_dead_space_fill)
208
height += VERT_DEAD_SPACE_HEIGHT(mw);
210
#ifdef DRAW_RESIZE_LINE
211
XDrawLine(display, win, gc, x, y, x, y + height);
212
if (XtIsManaged(LeftClip(mw)))
213
XDrawLine(display, XtWindow(LeftClip(mw)), gc,
214
x - COLUMN_LABEL_OFFSET(mw), 0,
215
x - COLUMN_LABEL_OFFSET(mw),
216
LeftClip(mw)->core.height);
218
#ifdef DRAW_RESIZE_SHADOW
219
DRAW_SHADOW(display, win,
220
mw->matrix.resize_top_shadow_gc,
221
mw->matrix.resize_bottom_shadow_gc,
222
shadow_width, x, y, width, height, XmSHADOW_OUT);
223
if (XtIsManaged(LeftClip(mw)))
224
DRAW_SHADOW(display, XtWindow(LeftClip(mw)),
225
mw->matrix.resize_top_shadow_gc,
226
mw->matrix.resize_bottom_shadow_gc,
227
shadow_width, x - COLUMN_LABEL_OFFSET(mw),
228
0, width, LeftClip(mw)->core.height, XmSHADOW_OUT);
234
* Similarly for trailingFixedColumns - beware going off the clip child
237
if (column >= TRAILING_HORIZ_ORIGIN(mw) ||
238
x >= (int)(ClipChild(mw)->core.x + ClipChild(mw)->core.width))
240
y = ROW_LABEL_OFFSET(mw);
241
height = VISIBLE_HEIGHT(mw) + FIXED_ROW_HEIGHT(mw) +
242
TRAILING_FIXED_ROW_HEIGHT(mw);
245
if (need_vert_dead_space_fill)
246
height += VERT_DEAD_SPACE_HEIGHT(mw);
248
#ifdef DRAW_RESIZE_LINE
249
XDrawLine(display, win, gc, x, y, x, y + height);
250
if (XtIsManaged(RightClip(mw)))
251
XDrawLine(display, XtWindow(RightClip(mw)),
252
gc, x - TRAILING_FIXED_COLUMN_LABEL_OFFSET(mw), 0,
253
x - TRAILING_FIXED_COLUMN_LABEL_OFFSET(mw),
254
RightClip(mw)->core.height);
257
#ifdef DRAW_RESIZE_SHADOW
258
DRAW_SHADOW(display, win,
259
mw->matrix.resize_top_shadow_gc,
260
mw->matrix.resize_bottom_shadow_gc,
261
shadow_width, x, y, width, height, XmSHADOW_OUT);
262
if (XtIsManaged(RightClip(mw)))
263
DRAW_SHADOW(display, XtWindow(RightClip(mw)),
264
mw->matrix.resize_top_shadow_gc,
265
mw->matrix.resize_bottom_shadow_gc,
267
x - TRAILING_FIXED_COLUMN_LABEL_OFFSET(mw), 0,
268
width, RightClip(mw)->core.height, XmSHADOW_OUT);
273
xbaeGetVisibleRows(mw, &top, &bottom);
275
* we need all non-fixed rows, so add 1 to bottom
276
* to include the last one as the return values
282
* The area between top and bottom rows are the non fixed rows. They
283
* fall on the ClipChild
285
y = -mw->matrix.cell_shadow_thickness; /* relative to clip */
287
height = ROW_HEIGHT(mw) * (bottom - top) +
288
2 * mw->matrix.cell_shadow_thickness;
291
* If we are on the clip, the x location is offset by the
292
* fixed column width, label offset and label width
294
adjusted_x = x - FIXED_COLUMN_LABEL_OFFSET(mw);
296
win = XtWindow(ClipChild(mw));
298
#ifdef DRAW_RESIZE_LINE
299
XDrawLine(display, win, gc, adjusted_x, y, adjusted_x, y + height);
301
#ifdef DRAW_RESIZE_SHADOW
302
DRAW_SHADOW(display, win,
303
mw->matrix.resize_top_shadow_gc,
304
mw->matrix.resize_bottom_shadow_gc,
305
shadow_width, adjusted_x, y, width, height, XmSHADOW_OUT);
308
* Now draw the line (or shadow) on the non clipped region - that is
309
* the fixed and trailingFixed rows. First, do the leading rows.
311
if (mw->matrix.fixed_rows)
313
y = ROW_LABEL_OFFSET(mw);
314
height = FIXED_ROW_HEIGHT(mw) + 2 * mw->matrix.cell_shadow_thickness;
316
xbaeSetClipMask(mw, CLIP_FIXED_ROWS);
318
#ifdef DRAW_RESIZE_LINE
319
if (XtIsManaged(TopClip(mw)))
320
XDrawLine(display, XtWindow(TopClip(mw)), gc, adjusted_x,
321
-mw->matrix.cell_shadow_thickness, adjusted_x, height);
323
#ifdef DRAW_RESIZE_SHADOW
324
if (XtIsManaged(TopClip(mw)))
325
DRAW_SHADOW(display, XtWindow(TopClip(mw)),
326
mw->matrix.resize_top_shadow_gc,
327
mw->matrix.resize_bottom_shadow_gc,
328
shadow_width, adjusted_x,
329
-mw->matrix.cell_shadow_thickness,
330
width, height, XmSHADOW_OUT);
332
xbaeSetClipMask(mw, CLIP_NONE);
336
* The trailingFixedRows
338
if (mw->matrix.trailing_fixed_rows)
340
y = TRAILING_FIXED_ROW_LABEL_OFFSET(mw);
341
height = TRAILING_FIXED_ROW_HEIGHT(mw) +
342
2 * mw->matrix.cell_shadow_thickness;
344
clip_reason = CLIP_TRAILING_FIXED_ROWS;
345
if (IS_LEADING_FIXED_COLUMN(mw, column))
346
clip_reason |= CLIP_FIXED_COLUMNS;
347
else if (IS_TRAILING_FIXED_COLUMN(mw, column))
348
clip_reason |= CLIP_TRAILING_FIXED_COLUMNS;
350
xbaeSetClipMask(mw, clip_reason);
352
#ifdef DRAW_RESIZE_LINE
353
if (XtIsManaged(BottomClip(mw)))
354
XDrawLine(display, XtWindow(BottomClip(mw)), gc, adjusted_x,
355
-mw->matrix.cell_shadow_thickness, adjusted_x, height);
357
#ifdef DRAW_RESIZE_SHADOW
358
if (XtIsManaged(BottomClip(mw)))
359
DRAW_SHADOW(display, XtWindow(BottomClip(mw)),
360
mw->matrix.resize_top_shadow_gc,
361
mw->matrix.resize_bottom_shadow_gc,
362
shadow_width, adjusted_x,
363
-mw->matrix.cell_shadow_thickness,
364
width, height, XmSHADOW_OUT);
366
xbaeSetClipMask(mw, CLIP_NONE);
369
if ((NEED_VERT_FILL(mw) && (! HAS_ATTACHED_TRAILING_ROWS(mw))) ||
370
need_vert_dead_space_fill)
372
if (need_vert_dead_space_fill)
374
y = UNATTACHED_TRAILING_ROWS_OFFSET(mw) -
375
mw->matrix.cell_shadow_thickness;
376
height = 2 * mw->matrix.cell_shadow_thickness +
377
VERT_DEAD_SPACE_HEIGHT(mw);
381
y = TRAILING_FIXED_ROW_LABEL_OFFSET(mw) +
382
TRAILING_FIXED_ROW_HEIGHT(mw);
383
height = FILL_VERT_HEIGHT(mw) - HORIZ_SB_SPACE(mw);
386
#ifdef DRAW_RESIZE_LINE
387
XDrawLine(display, XtWindow(mw), gc,
388
adjusted_x, y, adjusted_x, height);
390
#ifdef DRAW_RESIZE_SHADOW
391
DRAW_SHADOW(display, XtWindow(mw),
392
mw->matrix.resize_top_shadow_gc,
393
mw->matrix.resize_bottom_shadow_gc,
395
width, height, XmSHADOW_OUT);
402
SlideColumn(w, data, event, cont)
408
XbaeMatrixResizeColumnStruct *rd = (XbaeMatrixResizeColumnStruct *)data;
409
XMotionEvent *motionEvent;
410
Boolean relayout = False;
414
if (event->type == ButtonRelease)
416
DrawSlideColumn(rd->mw, rd->lastx);
417
XUngrabPointer(XtDisplay(w), CurrentTime);
420
* Remanage the VSB if we unmapped it earlier
423
XtManageChild(VertScrollChild(rd->mw));
425
if (rd->mw->matrix.resize_column_callback)
427
XbaeMatrixResizeColumnCallbackStruct call_data;
429
call_data.reason = XbaeResizeColumnReason;
430
call_data.event = event;
431
call_data.row = rd->row;
432
call_data.column = rd->column - 1;
433
call_data.which = rd->column - 1;
434
call_data.columns = rd->mw->matrix.columns;
435
call_data.column_widths = rd->columnWidths;
436
XtCallCallbackList ((Widget)rd->mw,
437
rd->mw->matrix.resize_column_callback,
438
(XtPointer)&call_data);
441
for (i = 0; i < rd->mw->matrix.columns; i++)
442
if (rd->columnWidths[i] != rd->mw->matrix.column_widths[i])
444
/* Make sure everything is handled correctly with SetValues */
445
XtVaSetValues((Widget)rd->mw, XmNcolumnWidths,
446
rd->columnWidths, NULL);
450
* If maxColumnLengths are set and we have resized the column to
451
* larger, reset the corresponding maxColumnLength
453
if (rd->mw->matrix.column_max_lengths &&
454
rd->columnWidths[rd->column - 1] >
455
rd->mw->matrix.column_max_lengths[rd->column - 1])
456
rd->mw->matrix.column_max_lengths[rd->column - 1] =
457
rd->columnWidths[rd->column - 1];
458
XtFree((char *)rd->columnWidths);
462
if (event->type != MotionNotify) /* Double check! */
465
motionEvent = (XMotionEvent *)event;
467
if (rd->currentx - motionEvent->x > FONT_WIDTH(rd->mw))
469
/* If we're only one character wide, we cannae get any smaller */
470
if (rd->columnWidths[rd->column - 1] == BAD_WIDTH + 1)
473
* Moved left a full character - update the column widths and force
476
numCharacters = (rd->currentx - motionEvent->x) /
478
if (numCharacters >= rd->columnWidths[rd->column - 1])
479
/* Must keep a column at least one character wide */
480
numCharacters = rd->columnWidths[rd->column - 1] - 1;
482
rd->columnWidths[rd->column - 1] -= numCharacters;
483
rd->currentx -= numCharacters * FONT_WIDTH(rd->mw);
487
if (motionEvent->x - rd->currentx > FONT_WIDTH(rd->mw))
490
* Moved right a full character - update the column widths and force
493
numCharacters = (motionEvent->x - rd->currentx) /
495
rd->columnWidths[rd->column - 1] += numCharacters;
496
rd->currentx += numCharacters * FONT_WIDTH(rd->mw);
502
/* Draw the marker line in the new location */
503
if (rd->lastx != rd->currentx)
505
DrawSlideColumn(rd->mw, rd->currentx);
506
DrawSlideColumn(rd->mw, rd->lastx);
508
rd->lastx = rd->currentx;
515
xbaeResizeColumnsACT(w, event, params, nparams)
527
static Cursor cursor;
528
XbaeMatrixResizeColumnStruct resizeData;
530
XtAppContext appcontext;
531
#ifdef DRAW_RESIZE_LINE
534
unsigned long gcmask, event_mask;
535
Display *display = XtDisplay(w);
536
#define FUZZ_FACTOR 3
537
int fuzzy = FUZZ_FACTOR;
541
* Get Matrix widget and make sure it is a Matrix subclass.
542
* w could be Matrix, or the Clip or textField children of Matrix
544
if (XtIsSubclass(w, xbaeMatrixWidgetClass))
545
mw = (XbaeMatrixWidget)w;
546
else if (XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass))
547
mw = (XbaeMatrixWidget)XtParent(w);
550
XtWidgetToApplicationContext(w),
551
"resizeColumnsACT", "badWidget", "XbaeMatrix",
552
"XbaeMatrix: Bad widget passed to ResizeColumns action",
558
* If we won't allow dynamic column resize, leave.
560
if (!mw->matrix.allow_column_resize)
563
if (!xbaeEventToXY(mw, event, &x, &y, &cell))
568
if (!xbaeXYToRowCol(mw, &x, &y, &row, &column, cell))
572
* Calculate if the x and y of the middle button event is on
573
* a column border. Allow the width of the shadow to be the
574
* allowed delta. x is modified in xbaeXYToRowCol() to be
575
* the x distance from the cell's border
577
if ((int)mw->matrix.cell_shadow_thickness > fuzzy)
578
fuzzy = mw->matrix.cell_shadow_thickness;
580
if (x > fuzzy && COLUMN_WIDTH(mw, column) - x > fuzzy)
584
* Looks like we hit a column border, determine the column that is
585
* intended to be resized
587
if ((COLUMN_WIDTH(mw, column) - x) <= fuzzy)
590
/* Can't adjust the origin or should you be able to?? */
595
* Make it here and it's time to start the fun stuff!
598
/* Create the left / right cursor */
600
cursor = XCreateFontCursor(display, XC_sb_h_double_arrow);
602
/* Commit any edit in progress and unmap the text field -
603
it's just bad luck */
604
(*((XbaeMatrixWidgetClass)XtClass(mw))->matrix_class.commit_edit)
608
* Redraw the cell that had the text field in it or it might stay blank
610
xbaeDrawCell(mw, mw->matrix.current_row, mw->matrix.current_column);
613
* Say goodbye to the Vertical ScrollBar -> it only gets in the way!
615
if ((resizeData.haveVSB = XtIsManaged(VertScrollChild(mw)) &&
616
((mw->matrix.scrollbar_placement == XmTOP_RIGHT) ||
617
(mw->matrix.scrollbar_placement == XmBOTTOM_RIGHT))))
618
XtUnmanageChild(VertScrollChild(mw));
620
* Flush the commit events out to the server. Otherwise, our changes
621
* to the GCs below have a bad effect.
623
XSync(display, False);
625
event_mask = PointerMotionMask | ButtonReleaseMask;
626
XtAddEventHandler(w, event_mask,
627
True, (XtEventHandler)SlideColumn,
628
(XtPointer)&resizeData);
630
XGrabPointer(display, XtWindow(w), True, event_mask,
631
GrabModeAsync, GrabModeAsync, XtWindow((Widget)mw),
632
cursor, CurrentTime);
634
/* Copy the columnWidth array */
635
resizeData.columnWidths =
636
(short *)XtMalloc(mw->matrix.columns * sizeof(short));
637
for (i = 0; i < mw->matrix.columns; i++)
638
resizeData.columnWidths[i] = mw->matrix.column_widths[i];
639
resizeData.grabbed = True;
641
resizeData.column = column;
642
resizeData.startx = resizeData.currentx = resizeData.lastx =
645
gcmask = GCForeground | GCBackground | GCFunction;
646
values.function = GXxor;
647
#ifdef DRAW_RESIZE_LINE
648
XGetGCValues(display, mw->matrix.draw_gc, gcmask, &save);
649
values.foreground = values.background = save.background;
651
XChangeGC(display, mw->matrix.draw_gc, gcmask, &values);
654
DrawSlideColumn(mw, resizeData.currentx);
656
appcontext = XtWidgetToApplicationContext(w);
658
while (resizeData.grabbed)
659
XtAppProcessEvent(appcontext, XtIMAll);
661
XtRemoveEventHandler(w, event_mask, True,
662
(XtEventHandler)SlideColumn,
663
(XtPointer)&resizeData);
665
#ifdef DRAW_RESIZE_LINE
666
XSetFunction(display, mw->matrix.draw_gc, GXcopy);
671
* Action to process a drag out
675
xbaeProcessDragACT(w, event, params, nparams)
686
XbaeMatrixProcessDragCallbackStruct call_data;
689
* Get Matrix widget and make sure it is a Matrix subclass.
690
* w could be Matrix, or the Clip or textField children of Matrix
692
if (XtIsSubclass(w, xbaeMatrixWidgetClass))
693
mw = (XbaeMatrixWidget)w;
694
else if (XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass))
695
mw = (XbaeMatrixWidget)XtParent(w);
698
XtWidgetToApplicationContext(w),
699
"processDragACT", "badWidget", "XbaeMatrix",
700
"XbaeMatrix: Bad widget passed to ProcessDrag action",
705
if (!mw->matrix.process_drag_callback)
708
if (!xbaeEventToXY(mw, event, &x, &y, &cell))
711
if (!xbaeXYToRowCol(mw, &x, &y, &row, &column, cell))
714
call_data.reason = XbaeProcessDragReason;
715
call_data.event = event;
717
call_data.column = column;
719
if (mw->matrix.draw_cell_callback)
721
Pixel bgcolor, fgcolor;
722
int width, height, depth;
724
call_data.type = xbaeGetDrawCellValue(
725
mw, row, column, &call_data.string, &call_data.pixmap,
726
&call_data.mask, &width, &height, &bgcolor, &fgcolor, &depth);
729
call_data.string = mw->matrix.cells ?
730
mw->matrix.cells[row][column] : "";
732
call_data.num_params = *nparams;
733
call_data.params = params;
735
XtCallCallbackList((Widget)mw, mw->matrix.process_drag_callback,
736
(XtPointer)&call_data);
741
* Action to edit a non-fixed cell.
745
xbaeEditCellACT(w, event, params, nparams)
754
static XrmQuark QPointer, QLeft, QRight, QUp, QDown;
755
static Boolean haveQuarks = False;
757
* Get static quarks for the parms we understand
761
QPointer = XrmPermStringToQuark("Pointer");
762
QLeft = XrmPermStringToQuark("Left");
763
QRight = XrmPermStringToQuark("Right");
764
QUp = XrmPermStringToQuark("Up");
765
QDown = XrmPermStringToQuark("Down");
770
* Get Matrix widget and make sure it is a Matrix subclass.
771
* w could be Matrix, or the Clip or textField children of Matrix
773
if (XtIsSubclass(w, xbaeMatrixWidgetClass))
774
mw = (XbaeMatrixWidget)w;
775
else if (XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass))
776
mw = (XbaeMatrixWidget)XtParent(w);
780
XtWidgetToApplicationContext(w),
781
"editCellACT", "badWidget", "XbaeMatrix",
782
"XbaeMatrix: Bad widget passed to EditCell action",
788
* Make sure we have a single parm
793
XtWidgetToApplicationContext(w),
794
"editCellACT", "badParms", "XbaeMatrix",
795
"XbaeMatrix: Wrong params passed to EditCell action, needs 1",
801
* Initialize row/column to the current position
803
row = mw->matrix.current_row;
804
column = mw->matrix.current_column;
807
* Quarkify the string param
809
q = XrmStringToQuark(params[0]);
812
* If we aren't currently editing, then the only kind of traversal that
813
* makes sense is pointer.
815
if (!XtIsManaged(TextChild(mw)) && q != QPointer)
820
CellType cellType = NonFixedCell;
824
* Get the x,y point coordinate relative to the Clip window.
825
* Return if this event did not occur in the Clip subwindow
826
* (since we can only edit non-fixed cells).
832
x = event->xbutton.x;
833
y = event->xbutton.y;
841
x = event->xmotion.x;
842
y = event->xmotion.y;
848
if (event->xbutton.subwindow == XtWindow(ClipChild(mw)))
850
x -= FIXED_COLUMN_LABEL_OFFSET(mw);
851
y -= FIXED_ROW_LABEL_OFFSET(mw);
852
cellType = NonFixedCell;
854
else if (event->xbutton.window != XtWindow(ClipChild(mw)))
856
if (!mw->matrix.traverse_fixed)
858
cellType = FixedCell;
862
* Convert the point to a row,column. If it does not pick a valid
865
if (!xbaeXYToRowCol(mw, &x, &y, &row, &column, cellType))
868
else if (q == QRight)
871
* If we are in the lower right corner, stay there.
872
* Otherwise move over a column. If we move off to the right of the
873
* final column to which traversing is allowed then move down a row
874
* and back to the first column to which traversing is allowed.
876
if (!mw->matrix.traverse_fixed)
878
/* check scrollable boundary */
879
if (mw->matrix.current_row != TRAILING_VERT_ORIGIN(mw) - 1 ||
880
mw->matrix.current_column != TRAILING_HORIZ_ORIGIN(mw) - 1)
883
if (IS_TRAILING_FIXED_COLUMN(mw, column))
885
column = mw->matrix.fixed_columns;
892
/* check matrix boundary */
893
if (mw->matrix.current_row != mw->matrix.rows - 1 ||
894
mw->matrix.current_column != mw->matrix.columns - 1)
897
if (column >= mw->matrix.columns)
908
* If we are in the upper left corner, stay there.
909
* Otherwise move back a column. If we move before the first column
910
* to which traversing is allowed, move up a row and over to the last
911
* column to which traversing is allowed.
913
if (!mw->matrix.traverse_fixed)
915
/* check scrollable boundary */
916
if (mw->matrix.current_row != mw->matrix.fixed_rows ||
917
mw->matrix.current_column != mw->matrix.fixed_columns)
920
if (IS_LEADING_FIXED_COLUMN(mw, column))
922
column = TRAILING_HORIZ_ORIGIN(mw) - 1;
929
if (mw->matrix.current_row != 0 || mw->matrix.current_column != 0)
934
column = mw->matrix.columns - 1;
944
/* adjust row for allowable traversable regions */
945
if (!mw->matrix.traverse_fixed)
947
if (IS_TRAILING_FIXED_ROW(mw, row))
948
row = mw->matrix.fixed_rows;
952
if (row >= mw->matrix.rows)
960
if (!mw->matrix.traverse_fixed)
962
if (IS_LEADING_FIXED_ROW(mw, row))
963
row = TRAILING_VERT_ORIGIN(mw) - 1;
968
row = mw->matrix.rows - 1;
973
* Call the traverseCellCallback to allow the application to
974
* perform custom traversal.
976
if (mw->matrix.traverse_cell_callback)
978
XbaeMatrixTraverseCellCallbackStruct call_data;
980
call_data.reason = XbaeTraverseCellReason;
981
call_data.event = event;
982
call_data.row = mw->matrix.current_row;
983
call_data.column = mw->matrix.current_column;
984
call_data.next_row = row;
985
call_data.next_column = column;
986
call_data.fixed_rows = mw->matrix.fixed_rows;
987
call_data.fixed_columns = mw->matrix.fixed_columns;
988
call_data.trailing_fixed_rows = mw->matrix.trailing_fixed_rows;
989
call_data.trailing_fixed_columns = mw->matrix.trailing_fixed_columns;
990
call_data.num_rows = mw->matrix.rows;
991
call_data.num_columns = mw->matrix.columns;
992
call_data.param = params[0];
993
call_data.qparam = q;
995
XtCallCallbackList((Widget)mw, mw->matrix.traverse_cell_callback,
996
(XtPointer)&call_data);
998
row = call_data.next_row;
999
column = call_data.next_column;
1003
* Attempt to edit the new cell using the edit_cell method.
1004
* If we are editing a cell based on pointer position, we always
1005
* call edit_cell. Otherwise, we must be editing a new cell to
1008
if (q == QPointer || (row != mw->matrix.current_row ||
1009
column != mw->matrix.current_column))
1010
(*((XbaeMatrixWidgetClass)XtClass(mw))->matrix_class.edit_cell)
1011
(mw, event, row, column, params, *nparams);
1014
* Traverse to the textField
1016
(void)XmProcessTraversal(TextChild(mw), XmTRAVERSE_CURRENT);
1020
* Action to unmap the textField and discard any edits made
1024
xbaeCancelEditACT(w, event, params, nparams)
1030
XbaeMatrixWidget mw;
1034
* Get Matrix widget and make sure it is a Matrix subclass.
1035
* w could be Matrix, or the Clip or textField children of Matrix
1037
if (XtIsSubclass(w, xbaeMatrixWidgetClass))
1038
mw = (XbaeMatrixWidget)w;
1039
else if (XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass))
1040
mw = (XbaeMatrixWidget)XtParent(w);
1044
XtWidgetToApplicationContext(w),
1045
"cancelEditACT", "badWidget", "XbaeMatrix",
1046
"XbaeMatrix: Bad widget passed to CancelEdit action",
1052
* Make sure we have a single param
1057
XtWidgetToApplicationContext(w),
1058
"cancelEditACT", "badParms", "XbaeMatrix",
1059
"XbaeMatrix: Wrong params passed to CancelEdit action, needs 1",
1065
* Validate our param
1067
if (!strcmp(params[0], "True"))
1069
else if (!strcmp(params[0], "False"))
1074
XtWidgetToApplicationContext(w),
1075
"cancelEditACT", "badParm", "XbaeMatrix",
1076
"XbaeMatrix: Bad parameter for CancelEdit action",
1081
* Call the cancel_edit method
1083
(*((XbaeMatrixWidgetClass)XtClass(mw))->matrix_class.cancel_edit)
1088
* Action save any edits made and unmap the textField if params[0] is True
1092
xbaeCommitEditACT(w, event, params, nparams)
1098
XbaeMatrixWidget mw;
1102
* Get Matrix widget and make sure it is a Matrix subclass.
1103
* w could be Matrix, or the Clip or textField children of Matrix
1105
if (XtIsSubclass(w, xbaeMatrixWidgetClass))
1106
mw = (XbaeMatrixWidget)w;
1107
else if (XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass))
1108
mw = (XbaeMatrixWidget)XtParent(w);
1112
XtWidgetToApplicationContext(w),
1113
"commitEditACT", "badWidget", "XbaeMatrix",
1114
"XbaeMatrix: Bad widget passed to CommitEdit action",
1120
* Make sure we have a single param
1125
XtWidgetToApplicationContext(w),
1126
"commitEditACT", "badParms", "XbaeMatrix",
1127
"XbaeMatrix: Wrong params for CommitEdit action, needs 1",
1133
* Validate our param
1135
if (!strcmp(params[0], "True"))
1137
else if (!strcmp(params[0], "False"))
1142
XtWidgetToApplicationContext(w),
1143
"commitEditACT", "badParm", "XbaeMatrix",
1144
"XbaeMatrix: Bad parameter for CommitEdit action",
1149
(void)(*((XbaeMatrixWidgetClass)XtClass(mw))->matrix_class.commit_edit)
1154
DoubleClick(mw, event, row, column)
1155
XbaeMatrixWidget mw;
1160
/* A double click in this instance is two clicks in the
1161
same cell in a time period < double_click_interval */
1163
unsigned long delta;
1166
if (event->type == ButtonRelease)
1168
/* If the button is released, store the current location and time -
1169
next time through, if it's a button press event, we check for
1171
mw->matrix.last_row = row;
1172
mw->matrix.last_column = column;
1173
if (ret) /* just had a double click */
1174
mw->matrix.last_click_time = (Time)0;
1176
mw->matrix.last_click_time = event->xbutton.time;
1181
current_time = event->xbutton.time;
1182
delta = current_time - mw->matrix.last_click_time;
1184
if (row == mw->matrix.last_row && column == mw->matrix.last_column &&
1185
delta < (unsigned long)mw->matrix.double_click_interval)
1195
PushButton(w, data, event, cont)
1201
XbaeMatrixButtonPressedStruct *button =
1202
(XbaeMatrixButtonPressedStruct *)data;
1203
XMotionEvent *motionEvent;
1206
Boolean pressed = button->pressed;
1209
if (event->type == ButtonRelease)
1211
button->grabbed = False;
1215
if (button->pressed)
1217
/* If the button is still pressed, it has been released in the
1218
same button that was pressed. "Unpress" it and call the
1220
if (button->column == -1)
1221
xbaeDrawRowLabel(button->mw, button->row, False);
1222
else if (button->row == -1)
1223
xbaeDrawColumnLabel(button->mw, button->column, False);
1225
if (button->mw->matrix.label_activate_callback)
1227
XbaeMatrixLabelActivateCallbackStruct call_data;
1229
call_data.reason = XbaeLabelActivateReason;
1230
call_data.event = event;
1231
call_data.row_label = (button->column == -1);
1232
call_data.row = button->row;
1233
call_data.column = button->column;
1235
if (button->column == -1)
1237
button->mw->matrix.row_labels[button->row];
1240
button->mw->matrix.column_labels[button->column];
1242
XtCallCallbackList((Widget)button->mw,
1243
button->mw->matrix.label_activate_callback,
1244
(XtPointer)&call_data);
1250
if (event->type != MotionNotify) /* We want to be sure about this! */
1253
motionEvent = (XMotionEvent *)event;
1257
if (!xbaeEventToXY(button->mw, event, &x, &y, &cell))
1260
if (xbaeXYToRowCol(button->mw, &x, &y, &row, &column, cell))
1261
/* Moved off the labels */
1265
if (button->column != column || button->row != row)
1266
/* Moved out of the button that was originally pressed */
1268
else if (button->column == column || button->row == row)
1271
/* If the status of whether or not the button should be pressed has
1272
changed, redraw the appropriate visual */
1273
if (pressed != button->pressed)
1275
if (button->column == -1)
1276
xbaeDrawRowLabel(button->mw, button->row, pressed);
1277
else if (button->row == -1)
1278
xbaeDrawColumnLabel(button->mw, button->column, pressed);
1279
/* And set our struct's pressed member to the current setting */
1280
button->pressed = pressed;
1286
xbaeHandleClick(w, data, event, cont)
1292
XbaeMatrixWidget mw = (XbaeMatrixWidget)data;
1296
Boolean translation;
1298
/* if we have a double click and a callback - break out! */
1299
if (event->type != ButtonPress && event->type != ButtonRelease)
1302
if (!xbaeEventToXY(mw, event, &x, &y, &cell))
1305
translation = xbaeXYToRowCol(mw, &x, &y, &row, &column, cell);
1308
(mw->matrix.button_labels ||
1309
(row == -1 && mw->matrix.column_button_labels &&
1310
mw->matrix.column_button_labels[column]) ||
1311
(column == -1 && mw->matrix.row_button_labels &&
1312
mw->matrix.row_button_labels[row])) &&
1313
((row == -1) ^ (column == -1)))
1315
unsigned long event_mask;
1316
XtAppContext appcontext;
1317
XbaeMatrixButtonPressedStruct button;
1319
/* If the row and column are invalid, return. If it is ButtonRelease
1320
event, also return - the ButtonRelease events are handled in the
1321
event handler loop below */
1322
if (event->type != ButtonPress)
1325
if (column == -1 && event->type == ButtonPress)
1327
xbaeDrawRowLabel(mw, row, True);
1328
else if (row == -1 && event->type == ButtonPress)
1330
xbaeDrawColumnLabel(mw, column, True);
1332
/* Action stations! */
1333
event_mask = ButtonReleaseMask | PointerMotionMask;
1337
XtAddGrab(w, True, False);
1338
/* Copy the data needed to be passed to the event handler */
1341
button.column = column;
1342
button.pressed = True;
1343
button.grabbed = True;
1345
XtAddEventHandler(w, event_mask,
1346
True, (XtEventHandler)PushButton,
1347
(XtPointer)&button);
1348
XtAddEventHandler(TextChild(mw), event_mask,
1349
True, (XtEventHandler)PushButton,
1350
(XtPointer)&button);
1352
appcontext = XtWidgetToApplicationContext(w);
1354
while (button.grabbed)
1355
XtAppProcessEvent(appcontext, XtIMAll);
1357
XtRemoveEventHandler(w, event_mask, True,
1358
(XtEventHandler)PushButton,
1359
(XtPointer)&button);
1360
XtRemoveEventHandler(TextChild(mw), event_mask, True,
1361
(XtEventHandler)PushButton,
1362
(XtPointer)&button);
1365
else if (translation && mw->matrix.default_action_callback &&
1367
DoubleClick(mw, event, mw->matrix.current_row,
1368
mw->matrix.current_column))
1370
/* Put this as an else -> we don't want double clicks on labels
1372
XbaeMatrixDefaultActionCallbackStruct call_data;
1374
if (row == -1 || column == -1)
1377
call_data.reason = XbaeDefaultActionReason;
1378
call_data.event = event;
1379
call_data.row = row;
1380
call_data.column = column;
1382
XtCallCallbackList((Widget)mw, mw->matrix.default_action_callback,
1383
(XtPointer)&call_data);
1389
xbaeSelectCellACT(w, event, params, nparams)
1395
XbaeMatrixWidget mw;
1399
XbaeMatrixSelectCellCallbackStruct call_data;
1402
* Get Matrix widget and make sure it is a Matrix subclass.
1403
* w could be Matrix, or the Clip or textField children of Matrix
1405
if (XtIsSubclass(w, xbaeMatrixWidgetClass))
1406
mw = (XbaeMatrixWidget)w;
1407
else if (XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass))
1408
mw = (XbaeMatrixWidget)XtParent(w);
1412
XtWidgetToApplicationContext(w),
1413
"xbaeSelectCellACT", "badWidget", "XbaeMatrix",
1414
"XbaeMatrix: Bad widget passed to SelectCell action",
1420
* If we don't have a selectCellCallback, then return now
1422
if (!mw->matrix.select_cell_callback)
1425
if (!xbaeEventToXY(mw, event, &x, &y, &cell))
1429
* Convert the point to a row,column. If it does not pick a valid
1430
* cell, then return. If button up then use the last selected cell
1431
* to make sure a valid button up event occurs when dragging out of
1434
if (!xbaeXYToRowCol(mw, &x, &y, &row, &column, cell))
1436
if (event->type == ButtonRelease)
1438
column = last_selected_column;
1439
row = last_selected_row;
1448
* Call our select_cell callbacks
1450
call_data.reason = XbaeSelectCellReason;
1451
call_data.event = event;
1455
call_data.row = last_row;
1456
call_data.column = last_column;
1460
call_data.row = row;
1461
call_data.column = column;
1464
last_selected_column = call_data.column;
1465
last_selected_row = call_data.row;
1467
call_data.selected_cells = mw->matrix.selected_cells;
1468
call_data.cells = mw->matrix.cells;
1469
call_data.num_params = *nparams;
1470
call_data.params = params;
1472
XtCallCallbackList((Widget)mw, mw->matrix.select_cell_callback,
1473
(XtPointer)&call_data);
1479
xbaeTraverseNextACT(w, event, params, nparams)
1485
XbaeMatrixWidget mw;
1488
* Get Matrix widget and make sure it is a Matrix subclass.
1489
* w should be the textField widget.
1491
if (XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass))
1492
mw = (XbaeMatrixWidget)XtParent(w);
1496
XtWidgetToApplicationContext(w),
1497
"traverseNextACT", "badWidget", "XbaeMatrix",
1498
"XbaeMatrix: Bad widget passed to TraverseNext action",
1504
* Set the traversing direction flag. XmProcessTraversal may traverse
1505
* to the Clip widget. If it does, then we will see this flag in
1506
* the Clip focusCallback, TraverseInCB, and we will continue to traverse
1507
* on out of the mw. yuck!
1509
mw->matrix.traversing = XmTRAVERSE_NEXT_TAB_GROUP;
1510
(void)XmProcessTraversal(TextChild(mw), XmTRAVERSE_NEXT_TAB_GROUP);
1511
mw->matrix.traversing = NOT_TRAVERSING;
1516
xbaeTraversePrevACT(w, event, params, nparams)
1522
XbaeMatrixWidget mw;
1525
* Get Matrix widget and make sure it is a Matrix subclass.
1526
* w should be the textField widget.
1528
if (XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass))
1529
mw = (XbaeMatrixWidget)XtParent(w);
1533
XtWidgetToApplicationContext(w),
1534
"traversePrevACT", "badWidget", "XbaeMatrix",
1535
"XbaeMatrix: Bad widget passed to TraversePrev action",
1541
* Set the traversing direction flag. XmProcessTraversal may traverse
1542
* to the Clip widget. If it does, then we will see this flag in
1543
* the Clip focusCallback, TraverseInCB, and we will continue to traverse
1544
* on out of the mw. yuck!
1546
mw->matrix.traversing = (int)XmTRAVERSE_PREV_TAB_GROUP;
1547
(void)XmProcessTraversal(TextChild(mw), XmTRAVERSE_PREV_TAB_GROUP);
1548
mw->matrix.traversing = NOT_TRAVERSING;
1552
callSelectCellAction(mw, event)
1553
XbaeMatrixWidget mw;
1556
XbaeMatrixSelectCellCallbackStruct call_data;
1557
Boolean old_scroll_select = mw->matrix.scroll_select;
1559
mw->matrix.scroll_select = False;
1561
call_data.reason = XbaeSelectCellReason;
1562
call_data.event = event;
1563
call_data.row = last_row;
1564
call_data.column = last_column;
1565
call_data.selected_cells = mw->matrix.selected_cells;
1566
call_data.cells = mw->matrix.cells;
1567
call_data.num_params = 1;
1568
call_data.params = (char **)XtMalloc(sizeof(char *));
1569
call_data.params[0] = "extend";
1572
(Widget)mw, mw->matrix.select_cell_callback,
1573
(XtPointer)&call_data);
1575
(void)XtFree((char *)call_data.params);
1577
mw->matrix.scroll_select = old_scroll_select;
1583
checkScrollValues(w, data, event, cont)
1589
XbaeMatrixScrollStruct *ss = (XbaeMatrixScrollStruct *)data;
1590
XMotionEvent *motionEvent;
1602
if (event->type == ButtonRelease)
1604
XtRemoveTimeOut(ss->timerID);
1605
ss->grabbed = False;
1607
if (ss->mw->matrix.selection_policy == XmMULTIPLE_SELECT ||
1608
ss->mw->matrix.selection_policy == XmEXTENDED_SELECT)
1609
callSelectCellAction(ss->mw, ss->event);
1614
if (!xbaeEventToXY(ss->mw, event, &x, &y, &cell))
1617
motionEvent = (XMotionEvent *)event;
1620
* In this instance, we don't care if a valid row and column are
1621
* returned as we'll be the judge of the result
1623
inMatrix = xbaeXYToRowCol(ss->mw, &x, &y, &row, &column, cell);
1626
* Reset the flags, so the matrix stops scrolling when the
1627
* pointer is moved back into the fixed columns/rows after a drag
1628
* select in the fixed columns/rows which caused the matrix to
1629
* scroll vertically/horizontally.
1636
if (inMatrix && cell == NonFixedCell)
1644
* Calculate our position relative to the clip and adjust.
1646
if (motionEvent->y >= (int)(ss->cw->core.y + ss->cw->core.height))
1648
/* Below the matrix */
1649
distance = motionEvent->y - ss->cw->core.y - ss->cw->core.height;
1653
* If we are below the matrix, the current column may have
1654
* still changed from horizontal motion.
1657
while (COLUMN_POSITION(ss->mw, i) < HORIZ_ORIGIN(ss->mw) +
1661
if (i <= ss->mw->matrix.columns && i > 0)
1662
last_column = i - 1;
1664
else if (motionEvent->y <= ss->cw->core.y)
1667
* Above the matrix - can't be both above and below at the same
1668
* time unless we have two mouses!
1670
distance = ss->cw->core.y - motionEvent->y;
1674
while (COLUMN_POSITION(ss->mw, i) < HORIZ_ORIGIN(ss->mw) +
1677
if (i > 0 && i <= ss->mw->matrix.columns)
1678
last_column = i - 1;
1680
if (motionEvent->x <= ss->cw->core.x)
1685
distance = Min(distance, ss->cw->core.x - motionEvent->x);
1687
* Check for any vertical motion
1689
if (!ss->below && !ss->above)
1691
last_row = YtoRow(ss->mw, motionEvent->y -
1692
COLUMN_LABEL_HEIGHT(ss->mw)) +
1693
VERT_ORIGIN(ss->mw);
1694
SANITY_CHECK_ROW(ss->mw, last_row);
1697
else if (motionEvent->x >= (int)(ss->cw->core.x + ss->cw->core.width))
1702
distance = Min(distance, (int)(motionEvent->x - ss->cw->core.x -
1703
ss->cw->core.width));
1704
if (!ss->below && !ss->above)
1706
last_row = YtoRow(ss->mw, motionEvent->y -
1707
COLUMN_LABEL_HEIGHT(ss->mw)) +
1708
VERT_ORIGIN(ss->mw);
1709
SANITY_CHECK_ROW(ss->mw, last_row);
1713
* Adjust the value of the update interval based on the distance we
1714
* are away from the matrix
1716
halfRows = distance / (ROW_HEIGHT(ss->mw) / 2);
1718
* Avoid use of the math library by doing a simple calculation
1720
for (i = 0; i < halfRows; i++)
1723
ss->interval = DEFAULT_SCROLL_SPEED / (denom > 0 ? denom : 1);
1725
if (ss->interval <= 0) /* Just to be on the safe side */
1734
XbaeMatrixScrollStruct *ss = (XbaeMatrixScrollStruct *)data;
1735
Boolean callCallback = False;
1736
static int my_last_row = -1, my_last_column = -1;
1741
if (my_last_column != last_column || my_last_row != last_row)
1742
callCallback = True;
1744
my_last_row = last_row;
1745
my_last_column = last_column;
1747
* Off the clip widget - check there are cells that could
1748
* be scrolled into a visible position. If there are,
1749
* scroll them into view. If not, start setting the fixed
1750
* rows and columns as the current row and column.
1752
if (ss->below && last_row < TRAILING_VERT_ORIGIN(ss->mw) - 1)
1754
xbaeMakeRowVisible(ss->mw, ++last_row);
1755
callCallback = True;
1757
else if (ss->above && last_row > (int)ss->mw->matrix.fixed_rows)
1759
xbaeMakeRowVisible(ss->mw, --last_row);
1760
callCallback = True;
1762
if (ss->right && last_column < TRAILING_HORIZ_ORIGIN(ss->mw) - 1)
1764
xbaeMakeColumnVisible(ss->mw, ++last_column);
1765
callCallback = True;
1767
else if (ss->left && last_column > (int)ss->mw->matrix.fixed_columns)
1769
xbaeMakeColumnVisible(ss->mw, --last_column);
1770
callCallback = True;
1774
(ss->mw->matrix.selection_policy == XmMULTIPLE_SELECT ||
1775
ss->mw->matrix.selection_policy == XmEXTENDED_SELECT))
1776
callSelectCellAction(ss->mw, ss->event);
1779
* Flush the updates out to the server so we don't end up lagging
1780
* behind too far and end up with a million redraw requests.
1781
* Particularly for higher update speeds
1783
XFlush(XtDisplay((Widget)ss->mw));
1785
ss->timerID = XtAppAddTimeOut(
1786
ss->app_context, ss->interval, (XtTimerCallbackProc)updateScroll,
1792
xbaeHandleMotionACT(w, event, params, nparams)
1798
XbaeMatrixWidget mw;
1800
XMotionEvent *motionEvent;
1801
XButtonEvent *buttonEvent;
1802
int x, y, row, column;
1810
* Get Matrix widget and make sure it is a Matrix subclass.
1811
* w could be Matrix, or the Clip or textField children of Matrix
1813
if (XtIsSubclass(w, xbaeMatrixWidgetClass))
1814
mw = (XbaeMatrixWidget)w;
1815
else if (XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass))
1816
mw = (XbaeMatrixWidget)XtParent(w);
1819
XtWidgetToApplicationContext(w),
1820
"handleMotionACT", "badWidget", "XbaeMatrix",
1821
"XbaeMatrix: Bad widget passed to HandleMotion action",
1825
motionEvent = (XMotionEvent *)event;
1826
buttonEvent = (XButtonEvent *)event;
1828
cw = (XbaeClipWidget)ClipChild(mw);
1830
if (!xbaeEventToXY(mw, event, &x, &y, &cell))
1834
* In this instance, we don't care if a valid row and column are
1835
* returned as we'll be the judge of the result
1837
inMatrix = xbaeXYToRowCol(mw, &x, &y, &row, &column, cell);
1839
if (inMatrix && cell == NonFixedCell)
1842
* If we are in a NonFixedCell, then we're cruisin'. Just
1843
* update our position
1845
if (row != last_row || column != last_column)
1847
if (row < mw->matrix.rows && column < mw->matrix.columns)
1850
last_column = column;
1852
if (mw->matrix.selection_policy == XmMULTIPLE_SELECT ||
1853
mw->matrix.selection_policy == XmEXTENDED_SELECT)
1854
callSelectCellAction(mw, event);
1860
XbaeMatrixScrollStruct scrollData;
1864
* Grab the pointer and add a timeout routine to start modifying
1865
* the current row and/or column in the matrix. Also add an
1866
* event handler to monitor the current distance outside the
1867
* matrix so we can adjust the timeout routine to go faster when
1868
* the pointer is further away from the matrix.
1873
XtAddGrab(w, True, False);
1877
scrollData.event = event;
1878
scrollData.interval = DEFAULT_SCROLL_SPEED;
1879
scrollData.inClip = False;
1880
scrollData.grabbed = True;
1881
scrollData.app_context = XtWidgetToApplicationContext(w);
1882
scrollData.above = scrollData.below = False;
1883
scrollData.left = scrollData.right = False;
1885
XtAddEventHandler(w, PointerMotionMask | ButtonReleaseMask,
1886
True, (XtEventHandler)checkScrollValues,
1887
(XtPointer)&scrollData);
1889
* Call checkScrollValues() to find out where exactly we are in
1890
* relation to the clip widget
1892
checkScrollValues(w, (XtPointer)&scrollData, event, &cont);
1895
* The above / below / left / right members of the scrollData struct
1896
* should now be set so we know where we should be moving. Let's
1897
* get on with it, eh?
1899
updateScroll((XtPointer)&scrollData);
1901
while (scrollData.grabbed && !scrollData.inClip)
1902
XtAppProcessEvent(scrollData.app_context, XtIMAll);
1904
XtRemoveEventHandler(w, PointerMotionMask | ButtonReleaseMask,
1905
True, (XtEventHandler)checkScrollValues,
1906
(XtPointer)&scrollData);
1910
* We don't want the timeout getting called again as, in two lines,
1911
* we'll be way out of scope!
1913
XtRemoveTimeOut(scrollData.timerID);
1920
xbaePageDownACT(w, event, params, nparams)
1926
XbaeMatrixWidget mw;
1930
* Get Matrix widget and make sure it is a Matrix subclass.
1931
* w should be the textField widget.
1933
if (XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass))
1934
mw = (XbaeMatrixWidget)XtParent(w);
1938
XtWidgetToApplicationContext(w),
1939
"pageDownACT", "badWidget", "XbaeMatrix",
1940
"XbaeMatrix: Bad widget passed to PageDown action",
1945
if (!XtIsManaged(VertScrollChild(mw)))
1949
* Save the top row - if scrolling occurs, the text widget needs
1952
top = VERT_ORIGIN(mw);
1954
XtCallActionProc(VertScrollChild(mw), "PageDownOrRight",
1957
if (VERT_ORIGIN(mw) != top)
1959
* Position the cursor at the top most non fixed row if there was
1962
XbaeMatrixEditCell((Widget)mw, VERT_ORIGIN(mw) +
1963
mw->matrix.fixed_rows, mw->matrix.current_column);
1968
xbaePageUpACT(w, event, params, nparams)
1974
XbaeMatrixWidget mw;
1979
* Get Matrix widget and make sure it is a Matrix subclass.
1980
* w should be the textField widget.
1982
if (XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass))
1983
mw = (XbaeMatrixWidget)XtParent(w);
1987
XtWidgetToApplicationContext(w),
1988
"pageUpACT", "badWidget", "XbaeMatrix",
1989
"XbaeMatrix: Bad widget passed to PageUp action",
1994
if (!XtIsManaged(VertScrollChild(mw)))
1998
* Save the top row - if scrolling occurs, the text widget needs
2001
top = VERT_ORIGIN(mw);
2003
XtCallActionProc(VertScrollChild(mw), "PageUpOrLeft",
2006
if (VERT_ORIGIN(mw) != top)
2008
* Position the cursor at the top most non fixed row if there was
2011
XbaeMatrixEditCell((Widget)mw, VERT_ORIGIN(mw) +
2012
mw->matrix.fixed_rows, mw->matrix.current_column);