123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938 |
- MODULE WMGrids; (** AUTHOR "TF"; PURPOSE "Generic grid component"; *)
- IMPORT
- Inputs, XML, WMComponents,
- WMStandardComponents, Strings, Graphics := WMGraphics, WMRectangles,
- WMProperties, WMEvents,
- WM := WMWindowManager;
- TYPE
- (* Local type - alias for convenience *)
- String = Strings.String;
- (* return the desired size of the cell. Only used for auto-sizing. *)
- MeasureCellProc* = PROCEDURE {DELEGATE} (x, y : LONGINT; VAR width, height : LONGINT);
- (** Draw the cell (from 0, 0 to w, h) into canvas. state may include ??? *)
- DrawCellProc* = PROCEDURE {DELEGATE} (canvas : Graphics.Canvas; w, h : LONGINT; state : SET; x, y : LONGINT);
- (** Return the number of cells spaned in x an d y direction. *)
- GetCellSpansProc* = PROCEDURE {DELEGATE} (x, y : LONGINT; VAR spanx, spany : LONGINT);
- GetCellStateProc* = PROCEDURE {DELEGATE} (x, y : LONGINT) : SET;
- Spacings* = POINTER TO ARRAY OF LONGINT;
- CONST
- CellHighlighted* = 0; CellSelected* = 1; CellFocused* = 2; CellFixed* = 3;
- GridSelectNone* = 0; (** not selectable *)
- GridSelectSingleCell* = 1; (** only a single cell can be selected *)
- GridSelectSingleCol* = 2; (** only a single column can be selected *)
- GridSelectSingleRow* = 3; (** only a single row can be selected *)
- GridSelectHorizontal = 4; (** horizontal strips can be selected *)
- GridSelectVertical = 5; (** vertical strips can be selected *)
- GridSelectCols* = 6; (** only columns can be selected *)
- GridSelectRows* = 7; (** only rows can be selected *)
- GridSelectBlock* = 8;
- CONST
- PixelRange = 2; (* sensitive pixels left and right of a column/row separation *)
- DragDist = 10;
- TYPE
- CellPos* = RECORD col*, row* : LONGINT END;
- CellPositionInfo* = OBJECT
- VAR
- pos* : CellPos;
- END CellPositionInfo;
- (** Generic grid component. Supports :
- Spacing : equal/variable row / column spacing
- Number of fixed rows/colums (Fixed cells may NOT span multiple colums or rows)
- Cells can span multiple rows and/or colums
- *)
- GenericGrid* = OBJECT(WMComponents.VisualComponent)
- VAR
- getCellSpans : GetCellSpansProc;
- drawCell : DrawCellProc;
- getCellState : GetCellStateProc;
- tableStart* : CellPos;
- state, tempState : Graphics.CanvasState;
- scrollx-, scrolly- : WMStandardComponents.Scrollbar;
- showScrollX-, showScrollY- : WMProperties.BooleanProperty; (* show scrollbars if needed *)
- showScrollXC, showScrollYC : BOOLEAN;
- alwaysShowScrollX-, alwaysShowScrollY- : WMProperties.BooleanProperty; (* always show scrollbars even if not needed, overruled by showScroll *)
- alwaysShowScrollXC, alwaysShowScrollYC : BOOLEAN;
- nofRows-, nofCols-, cellDist- : WMProperties.Int32Property;
- nofRowsC, nofColsC, cellDistC : LONGINT; (* internal count of rows and colums *)
- rowHeights, colWidths : Spacings; (* variable sizes of rows and cols *)
- fixedCols-, fixedRows- : WMProperties.Int32Property; (* number of cols/rows that are fixed *)
- fixedColsC, fixedRowsC : LONGINT; (* internal cache of the respective property values *)
- defaultColWidth-, defaultRowHeight- : WMProperties.Int32Property;
- defaultColWidthC, defaultRowHeightC : LONGINT; (* internal cache of the respective property values *)
- allowColResize-, allowRowResize- : WMProperties.BooleanProperty;
- (**
- * If set to TRUE,
- * - clicking on a cell which is not completely visible will scroll the grid so it's visible
- * - when dragging and the pointer leaves the visible part of the grid, the grid is scrolled
- * default : TRUE;
- *)
- adjustFocusPosition- : WMProperties.BooleanProperty;
- focus, focusCell, highlight : CellPos; (* focusCell is the master Cell of focus *)
- selectionMode : LONGINT;
- selStart, selEnd : CellPos;
- selA : CellPos;
- selecting : BOOLEAN;
- drag : BOOLEAN;
- pointerInside : BOOLEAN; (* the last position of the pointer is needed for correct highlighting when scrolling with kb *)
- lastPointerX, lastPointerY :LONGINT;
- wasSelected- : BOOLEAN;
- onSelect- : WMEvents.EventSource;
- onClick- : WMEvents.EventSource;
- onClickSelected- : WMEvents.EventSource;
- shiftDown : BOOLEAN;
- hasOldPointer : BOOLEAN;
- prevPointerInfo : WM.PointerInfo;
- (* drag cell spacing *)
- dragCellSpacingNr : LONGINT;
- dragCellSpacingPos : LONGINT;
- dragCellSpacingWidth : BOOLEAN;
- dragCellSpacingHeight : BOOLEAN;
- downX, downY : LONGINT;
- dragPossible : BOOLEAN;
- selectOnPointerOver : BOOLEAN;
- lastkeys : SET;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- SetNameAsString(GSGenericGrid);
- takesFocus.Set(TRUE);
- NEW(scrollx); NEW(scrolly);
- AddInternalComponent(scrollx); AddInternalComponent(scrolly);
- scrollx.alignment.Set(WMComponents.AlignBottom);
- scrollx.vertical.Set(FALSE);
- scrolly.alignment.Set(WMComponents.AlignRight);
- scrolly.vertical.Set(TRUE);
- scrollx.onPositionChanged.Add(Scrolled);
- scrolly.onPositionChanged.Add(Scrolled);
- scrollx.pageSize.Set(1);
- scrolly.pageSize.Set(1);
- selectionMode := GridSelectSingleCell;
- selStart.col := -1; selStart.row := -1;
- selEnd.col := -1; selEnd.row := -1;
- highlight.col := -1; highlight.row := -1;
- (* properites *)
- NEW(defaultColWidth, defaultColWidthProto, NIL, NIL); properties.Add(defaultColWidth);
- NEW(defaultRowHeight, defaultRowHeightProto, NIL, NIL); properties.Add(defaultRowHeight);
- NEW(fixedCols, fixedColsProto, NIL, NIL); properties.Add(fixedCols);
- NEW(fixedRows, fixedRowsProto, NIL, NIL); properties.Add(fixedRows);
- NEW(allowColResize, allowColResizeProto, NIL, NIL); properties.Add(allowColResize);
- NEW(allowRowResize, allowRowResizeProto, NIL, NIL); properties.Add(allowRowResize);
- NEW(nofRows, nofRowsProto, NIL, NIL); properties.Add(nofRows);
- NEW(nofCols, nofColsProto, NIL, NIL); properties.Add(nofCols);
- NEW(cellDist, cellDistProto, NIL, NIL); properties.Add(cellDist);
- NEW(showScrollX, showScrollXProto, NIL, NIL); properties.Add(showScrollX);
- NEW(showScrollY, showScrollYProto, NIL, NIL); properties.Add(showScrollY);
- NEW(alwaysShowScrollX, alwaysShowScrollXProto, NIL, NIL); properties.Add(alwaysShowScrollX);
- NEW(alwaysShowScrollY, alwaysShowScrollYProto, NIL, NIL); properties.Add(alwaysShowScrollY);
- NEW(adjustFocusPosition, adjustFocusPositionProto, NIL, NIL); properties.Add(adjustFocusPosition);
- pointerInside := FALSE;
- selectOnPointerOver := FALSE;
- (* events *)
- NEW(onSelect, SELF, GSonSelect, GSonSelectInfo, SELF.StringToCompCommand); events.Add(onSelect);
- NEW(onClick, SELF, GSonClick, GSonClickInfo, SELF.StringToCompCommand); events.Add(onClick);
- NEW(onClickSelected, SELF, GSonClickSelected, GSonClickSelectedInfo, SELF.StringToCompCommand); events.Add(onClickSelected);
- END Init;
- PROCEDURE Initialize*; (*to do: drop this altogether*)
- BEGIN
- Initialize^;
- (*RecacheAllProperties*)
- END Initialize;
- PROCEDURE RecacheAllProperties;
- BEGIN
- defaultColWidthC := defaultColWidth.Get();
- defaultRowHeightC := defaultRowHeight.Get();
- fixedColsC := fixedCols.Get();
- fixedRowsC := fixedRows.Get();
- tableStart.row := Strings.Max(tableStart.row, fixedRowsC);
- tableStart.col := Strings.Max(tableStart.col, fixedColsC);
- nofRowsC := nofRows.Get();
- nofColsC := nofCols.Get();
- IF nofColsC = 1 THEN defaultColWidthC := bounds.GetWidth() END; (* list case *)
- cellDistC := cellDist.Get();
- showScrollXC := showScrollX.Get();
- showScrollYC := showScrollY.Get();
- alwaysShowScrollXC := alwaysShowScrollX.Get();
- alwaysShowScrollYC := alwaysShowScrollY.Get();
- CheckScrollbarsNeeded;
- AlignSubComponents
- END RecacheAllProperties;
- PROCEDURE RecacheProperties;
- BEGIN
- RecacheProperties^;
- RecacheAllProperties
- END RecacheProperties;
- PROCEDURE PropertyChanged*(sender, property : ANY);
- BEGIN
- RecacheAllProperties;
- Invalidate;
- PropertyChanged^(sender, property)
- END PropertyChanged;
- PROCEDURE GetColWidth*(i : LONGINT) : LONGINT;
- BEGIN
- CheckReadLock;
- IF colWidths = NIL THEN RETURN defaultColWidthC
- ELSIF (i < 0) OR (i > nofColsC) THEN RETURN 0
- ELSE
- IF i >= LEN(colWidths^) THEN RETURN defaultColWidthC ELSE RETURN colWidths[i] END
- END
- END GetColWidth;
- (** Set the width of columns. IF NIL, all columns have the default column width. If the spacings
- array is smaller than the number of columns, the additional columns have the default column width *)
- PROCEDURE SetColSpacings*(colWidths : Spacings);
- BEGIN
- Acquire;
- SELF.colWidths := colWidths;
- Invalidate();
- Release
- END SetColSpacings;
- (** returns a spacings array filled with the column width. The array contains only so many elements
- as the one set with SetColSpacings. The result is NIL, if not set with SetColSpacings *)
- PROCEDURE GetColSpacings*() : Spacings;
- VAR t : Spacings; i : LONGINT;
- BEGIN
- Acquire;
- IF colWidths # NIL THEN NEW(t, LEN(colWidths)); FOR i := 0 TO LEN(colWidths) - 1 DO t[i] := colWidths[i] END END;
- Release;
- RETURN t
- END GetColSpacings;
- (** Set the height of rows. IF NIL, all rows have the default row height. If the spacings
- array is smaller than the number of rows, the additional rows have the default row height *)
- PROCEDURE SetRowSpacings*(rowHeights : Spacings);
- BEGIN
- Acquire;
- SELF.rowHeights := rowHeights;
- Invalidate();
- Release
- END SetRowSpacings;
- (** returns a spacings array filled with the row heights. The array contains only so many elements
- as the one set with SetRowSpacings. The result is NIL, if not set with SetRowSpacings *)
- PROCEDURE GetRowSpacings*() : Spacings;
- VAR t : Spacings; i : LONGINT;
- BEGIN
- Acquire;
- IF rowHeights # NIL THEN NEW(t, LEN(rowHeights)); FOR i := 0 TO LEN(rowHeights) - 1 DO t[i] := rowHeights[i] END END;
- Release;
- RETURN t
- END GetRowSpacings;
- PROCEDURE SetSelectOnPointerOver*(select : BOOLEAN);
- BEGIN
- selectOnPointerOver := select;
- END SetSelectOnPointerOver;
- (** Scrollbars *)
- (** Define if the scrollbars should always be visible, if not needed. Overruled by ShowScrollbars *)
- PROCEDURE GetRowHeight*(i : LONGINT) : LONGINT;
- BEGIN
- CheckReadLock;
- IF rowHeights = NIL THEN RETURN defaultRowHeightC
- ELSIF (i < 0) OR (i > nofRowsC) THEN RETURN 0
- ELSE
- IF i >= LEN(rowHeights^) THEN RETURN defaultRowHeightC ELSE RETURN rowHeights[i] END
- END
- END GetRowHeight;
- PROCEDURE SetSelectionMode*(mode : LONGINT);
- BEGIN
- Acquire;
- IF mode # selectionMode THEN
- selectionMode := mode;
- Invalidate()
- END;
- Release
- END SetSelectionMode;
- PROCEDURE GetSelectionMode*():LONGINT;
- BEGIN
- RETURN selectionMode
- END GetSelectionMode;
- PROCEDURE SetDrawCellProc*(dcp :DrawCellProc);
- BEGIN
- Acquire;
- IF SELF.drawCell # dcp THEN
- SELF.drawCell := dcp;
- Invalidate()
- END;
- Release
- END SetDrawCellProc;
- PROCEDURE GetFixedPixels*(VAR w, h :LONGINT);
- VAR i : LONGINT;
- BEGIN
- w := 0; h := 0;
- FOR i := 0 TO fixedColsC - 1 DO INC(w, GetColWidth(i) + cellDistC) END;
- FOR i := 0 TO fixedRowsC - 1 DO INC(h, GetRowHeight(i) + cellDistC) END;
- END GetFixedPixels;
- PROCEDURE SetCellSpansProc*(gcsp : GetCellSpansProc); (* Dan *)
- BEGIN
- IF getCellSpans # gcsp THEN
- Acquire;
- getCellSpans := gcsp;
- Release
- END
- END SetCellSpansProc;
- PROCEDURE GetCellSpans(x, y : LONGINT; VAR spanx, spany : LONGINT);
- BEGIN
- IF getCellSpans # NIL THEN getCellSpans(x, y, spanx, spany)
- ELSE spanx := 1; spany := 1
- END
- END GetCellSpans;
- PROCEDURE IsSkipCell*(x, y : LONGINT) : BOOLEAN;
- VAR spanx, spany : LONGINT;
- BEGIN
- GetCellSpans(x, y, spanx, spany);
- RETURN (spanx = 0) OR (spany = 0)
- END IsSkipCell;
- PROCEDURE GetCellDimensions*(x, y : LONGINT; VAR width, height : LONGINT);
- VAR spanx, spany, i : LONGINT;
- BEGIN
- GetCellSpans(x, y, spanx, spany);
- width := -cellDistC; height := -cellDistC;
- FOR i := 0 TO spanx - 1 DO width := width + GetColWidth(x) + cellDistC END;
- FOR i := 0 TO spany - 1 DO height := height + GetRowHeight(y) + cellDistC END
- END GetCellDimensions;
- (* override by subclass *)
- PROCEDURE GetCellData*(col, row : LONGINT) : ANY;
- VAR position : CellPositionInfo;
- BEGIN
- NEW(position); position.pos.row := row; position.pos.col := col;
- RETURN position
- END GetCellData;
- PROCEDURE GetCellState(x, y : LONGINT) : SET;
- VAR state : SET;
- BEGIN
- IF getCellState # NIL THEN RETURN getCellState(x, y)
- ELSE
- state := {};
- IF (x = focus.col) & (y = focus.row) THEN state := state + {CellFocused} END;
- IF (x < fixedColsC) OR (y < fixedRowsC) THEN state := state + {CellFixed} END;
- CASE selectionMode OF
- | GridSelectSingleCell :
- IF (x = selStart.col) & (y = selStart.row) THEN state := state + {CellSelected} END;
- IF (x = highlight.col) & (y = highlight.row) THEN state := state + {CellHighlighted} END
- | GridSelectSingleCol, GridSelectCols :
- IF (x >= selStart.col) & (x <= selEnd.col) THEN state := state + {CellSelected} END;
- IF (x = highlight.col) THEN state := state + {CellHighlighted} END
- | GridSelectSingleRow, GridSelectRows :
- IF (y >= selStart.row) & (y <= selEnd.row) THEN state := state + {CellSelected} END;
- IF (y = highlight.row) THEN state := state + {CellHighlighted} END
- | GridSelectBlock, GridSelectHorizontal, GridSelectVertical :
- IF (x >= selStart.col) & (x <= selEnd.col) &(y >= selStart.row) & (y <= selEnd.row) THEN state := state + {CellSelected} END;
- IF (x = highlight.col) & (y = highlight.row) THEN state := state + {CellHighlighted} END;
- ELSE
- END;
- RETURN state
- END
- END GetCellState;
- (** col, row point to the master cell of (x, y). dx, dy are decreased by the respective decrement *)
- PROCEDURE FindMasterCell*(x, y : LONGINT; VAR col, row, xpos, ypos : LONGINT);
- VAR cw, ch : LONGINT;
- BEGIN
- col := x; row := y;
- GetCellSpans(col, row, cw, ch);
- WHILE (cw = 0) OR (ch = 0) DO
- IF cw = 0 THEN DEC(col); DEC(xpos, GetColWidth(col) + cellDistC) END;
- IF ch = 0 THEN DEC(row); DEC(ypos, GetRowHeight(row) + cellDistC) END;
- GetCellSpans(col, row, cw, ch)
- END
- END FindMasterCell;
- (* Find the cell at position x, y (also fixed cells are returned) *)
- PROCEDURE FindCellXY* (x, y : LONGINT; VAR col, row : LONGINT);
- VAR tx, ty, dummy : LONGINT;
- BEGIN
- GetFixedPixels(tx, ty);
- IF (x < tx) & (y < ty) THEN (* row and column fixed *)
- col := 0; row := 0; tx := 0; ty := 0;
- REPEAT tx := tx + GetColWidth(col) + cellDistC; INC(col) UNTIL (col >= fixedColsC) OR (tx >= x); DEC(col);
- REPEAT ty := ty + GetRowHeight(row) + cellDistC; INC(row) UNTIL (row >= fixedRowsC) OR (ty >= y); DEC(row);
- ELSIF (x < tx) THEN (* column fixed *)
- col := 0; row := tableStart.row; tx := 0;
- REPEAT tx := tx + GetColWidth(col) + cellDistC; INC(col) UNTIL (col >= fixedColsC) OR (tx >= x); DEC(col);
- REPEAT ty := ty + GetRowHeight(row) + cellDistC; INC(row) UNTIL (row >= nofRowsC) OR (ty >= y); DEC(row);
- ELSIF (y < ty) THEN (* row fixed *)
- col := tableStart.col; row := 0; ty := 0;
- REPEAT tx := tx + GetColWidth(col) + cellDistC; INC(col) UNTIL (col >= nofColsC) OR (tx >= x); DEC(col);
- REPEAT ty := ty + GetRowHeight(row) + cellDistC; INC(row) UNTIL (row >= fixedRowsC) OR (ty >= y); DEC(row);
- ELSE (* normal cells *)
- col := tableStart.col; row := tableStart.row;
- REPEAT tx := tx + GetColWidth(col) + cellDistC; INC(col) UNTIL (col >= nofColsC) OR (tx >= x); DEC(col);
- REPEAT ty := ty + GetRowHeight(row) + cellDistC; INC(row) UNTIL (row >= nofRowsC) OR (ty >= y); DEC(row);
- END;
- FindMasterCell(col, row, col, row, dummy, dummy)
- END FindCellXY;
- PROCEDURE CheckScrollbarsNeeded;
- VAR xmax, ymax : LONGINT;
- BEGIN
- xmax := nofColsC - 1; ymax := nofRowsC - 1;
- scrollx.max.Set(xmax); scrolly.max.Set(ymax);
- scrollx.visible.Set((alwaysShowScrollXC OR (xmax > 1)) & showScrollXC);
- scrolly.visible.Set((alwaysShowScrollYC OR (ymax > 1)) & showScrollYC)
- END CheckScrollbarsNeeded;
- PROCEDURE GetVisibleCellRect(col, row : LONGINT): WMRectangles.Rectangle;
- VAR x, y, i, tc, tr, tx, ty, w, h: LONGINT; rect : WMRectangles.Rectangle;
- BEGIN
- GetFixedPixels(tx, ty);
- IF (col < fixedColsC) & (row < fixedRowsC) THEN
- x := 0; FOR i := 0 TO col - 1 DO INC(x, GetColWidth(i) + cellDistC) END;
- y := 0; FOR i := 0 TO row -1 DO INC(y, GetRowHeight(i) + cellDistC) END
- ELSIF col < fixedColsC THEN
- x := 0; FOR i := 0 TO col - 1 DO INC(x, GetColWidth(i) + cellDistC) END;
- y := ty; FOR i := tableStart.row TO row -1 DO INC(y, GetRowHeight(i) + cellDistC) END
- ELSIF row < fixedRowsC THEN
- x := tx; FOR i := tableStart.col TO col - 1 DO INC(x, GetColWidth(i) + cellDistC) END;
- y := 0; FOR i := 0 TO row -1 DO INC(y, GetRowHeight(i) + cellDistC) END
- ELSE
- x := tx; FOR i := tableStart.col TO col - 1 DO INC(x, GetColWidth(i) + cellDistC) END;
- y := ty; FOR i := tableStart.row TO row -1 DO INC(y, GetRowHeight(i) + cellDistC) END;
- END;
- FindMasterCell(col, row, tc, tr, x, y);
- rect.l := x; rect.t := y;
- GetCellDimensions(tc, tr, w, h); rect.r := rect.l + w; rect.b := rect.t + h;
- RETURN rect
- END GetVisibleCellRect;
- PROCEDURE DrawBackground(canvas : Graphics.Canvas);
- VAR i, j, x, y, w, h, cw, ch, ti, tj, tx, ty, fx, fy : LONGINT;
- skip : BOOLEAN;
- r, clip : WMRectangles.Rectangle;
- BEGIN
- DrawBackground^(canvas);
- tableStart.row := Strings.Max(tableStart.row, fixedRowsC);
- tableStart.col := Strings.Max(tableStart.col, fixedColsC);
- canvas.GetClipRect(clip);
- canvas.SaveState(state); (* save the current clip-state for the scrollbars *)
- GetFixedPixels(fx, fy);
- (* draw both side fixed area *)
- y := 0;
- FOR j := 0 TO fixedRowsC - 1 DO
- x := 0; h := GetRowHeight(j);
- FOR i := 0 TO fixedColsC - 1 DO
- w := GetColWidth(i);
- r := WMRectangles.MakeRect(x, y, x + w, y + h);
- IF WMRectangles.Intersect(r, clip) THEN
- canvas.SetClipRect(r);
- canvas.ClipRectAsNewLimits(x, y);
- IF drawCell # NIL THEN drawCell(canvas, w, h, GetCellState(i, j), i, j) END;
- canvas.RestoreState(state)
- END;
- INC(x, w + cellDistC)
- END;
- INC(y, h + cellDistC)
- END;
- (* draw the fixed rows *)
- y := 0;
- FOR j := 0 TO fixedRowsC - 1 DO
- h := GetRowHeight(j);
- i := tableStart.col; x := fx;
- WHILE (i < nofColsC) & (x < bounds.GetWidth()) DO
- w := GetColWidth(i);
- r := WMRectangles.MakeRect(x, y, x + w, y + h);
- IF WMRectangles.Intersect(r, clip) THEN
- canvas.SetClipRect(r);
- canvas.ClipRectAsNewLimits(x, y);
- IF drawCell # NIL THEN drawCell(canvas, w, h, GetCellState(i, j), i, j) END;
- canvas.RestoreState(state)
- END;
- INC(i);
- INC(x, w + cellDistC)
- END;
- INC(y, h + cellDistC)
- END;
- (* draw the fixed columns *)
- y := fy;
- j := tableStart.row;
- WHILE (j < nofRowsC) & (y < bounds.GetHeight()) DO
- h := GetRowHeight(j);
- i := 0; x := 0;
- FOR i := 0 TO fixedColsC - 1 DO
- w := GetColWidth(i);
- r := WMRectangles.MakeRect(x, y, x + w, y + h);
- IF WMRectangles.Intersect(r, clip) THEN
- canvas.SetClipRect(r);
- canvas.ClipRectAsNewLimits(x, y);
- IF drawCell # NIL THEN drawCell(canvas, w, h, GetCellState(i, j), i, j) END;
- canvas.RestoreState(state)
- END;
- INC(x, w + cellDistC)
- END;
- INC(j);
- INC(y, h + cellDistC)
- END;
- (* draw the table *)
- canvas.SetClipRect(WMRectangles.MakeRect(fx, fy, bounds.GetWidth(), bounds.GetHeight()));
- canvas.ClipRectAsNewLimits(0, 0);canvas.SaveState(tempState);
- j := tableStart.row; y := fy;
- WHILE (j < nofRowsC) & (y < bounds.GetHeight()) DO
- i := tableStart.col; x := fx;
- h := GetRowHeight(j);
- WHILE (i < nofColsC) & (x < bounds.GetWidth()) DO
- w := GetColWidth(i);
- tx := x; ty := y; ti := i; tj := j;
- skip := IsSkipCell(ti, tj);
- IF (~skip) OR (i = tableStart.col) OR (j = tableStart.row) THEN
- IF skip THEN (* handle spans that leap in *)
- FindMasterCell(ti, tj, ti, tj, tx, ty);
- END;
- GetCellDimensions(ti, tj, cw, ch);
- r := WMRectangles.MakeRect(tx, ty, tx + cw, ty + ch);
- IF WMRectangles.Intersect(r, clip) THEN
- canvas.SetClipRect(r);
- canvas.ClipRectAsNewLimits(tx, ty);
- IF drawCell # NIL THEN drawCell(canvas, w, h, GetCellState(i, j), i, j) END;
- canvas.RestoreState(tempState)
- END
- END;
- INC(i); INC(x, w + cellDistC)
- END;
- INC(j); INC(y, h + cellDistC)
- END;
- canvas.RestoreState(state) (* restore the original clip-state *)
- END DrawBackground;
- PROCEDURE InvalidateCell*(col, row : LONGINT);
- BEGIN
- Acquire;
- InvalidateRect(GetVisibleCellRect(col, row));
- Release
- END InvalidateCell;
- PROCEDURE SetTopPosition*(col, row : LONGINT; updateScrollbar : BOOLEAN);
- BEGIN
- Acquire;
- col := Strings.Min(Strings.Max(col, fixedColsC), nofColsC - 1);
- row := Strings.Min(Strings.Max(row, fixedRowsC), nofRowsC - 1);
- IF (col # tableStart.col) OR (row # tableStart.row) THEN
- tableStart.col := col; tableStart.row := row;
- IF pointerInside THEN FindCellXY(lastPointerX, lastPointerY, highlight.col, highlight.row) END;
- Invalidate();
- IF updateScrollbar THEN scrollx.pos.Set(col); scrolly.pos.Set(row) END
- END;
- Release
- END SetTopPosition;
- PROCEDURE GetTopPosition*(VAR col, row : LONGINT);
- BEGIN
- Acquire;
- col := tableStart.col; row := tableStart.row;
- Release
- END GetTopPosition;
- PROCEDURE ScrollCellVisible(col, row : LONGINT);
- VAR cur : CellPos; r : WMRectangles.Rectangle; w, h: LONGINT;
- BEGIN
- cur := tableStart;
- w := bounds.GetWidth(); h := bounds.GetHeight();
- r := GetVisibleCellRect(col, row);
- WHILE (r.r > w) & (cur.col < col) DO DEC(r.r, GetColWidth(cur.col)); INC(cur.col) END;
- WHILE (r.b > h) & (cur.row < row) DO DEC(r.b, GetRowHeight(cur.row)); INC(cur.row) END;
- cur.col := Strings.Min(cur.col, col);
- cur.row := Strings.Min(cur.row, row);
- SetTopPosition(cur.col, cur.row, TRUE)
- END ScrollCellVisible;
- (* set the focus pos to col, row. The acutal focusCell is the master cell of col, row *)
- PROCEDURE SetFocusPos(col, row : LONGINT);
- VAR oldfocus : CellPos; dummy : LONGINT;
- BEGIN
- IF ~adjustFocusPosition.Get() THEN RETURN; END;
- oldfocus := focus; focus.col := col; focus.row := row;
- FindMasterCell(focus.col, focus.row, focusCell.col, focusCell.row, dummy, dummy);
- InvalidateCell(oldfocus.col, oldfocus.row); InvalidateCell(focusCell.col, focusCell.row);
- ScrollCellVisible(focusCell.col, focusCell.row)
- END SetFocusPos;
- PROCEDURE KeyEvent(ucs : LONGINT; flags: SET; VAR keysym: LONGINT);
- PROCEDURE AdjustSelection;
- BEGIN
- IF shiftDown THEN SetSelection(selA.col, selA.row, focus.col, focus.row)
- ELSE selA := focus; SetSelection(focus.col, focus.row, focus.col, focus.row)
- END
- END AdjustSelection;
- BEGIN
- shiftDown := Inputs.Shift * flags # {};
- IF (keysym = 0FF51H) & (focus.col > fixedColsC) THEN SetFocusPos(focus.col - 1, focus.row); AdjustSelection
- ELSIF (keysym = 0FF53H) & (focus.col < nofColsC - 1) THEN SetFocusPos(focus.col + 1, focus.row); AdjustSelection
- ELSIF (keysym = 0FF52H) & (focus.row > fixedRowsC) THEN SetFocusPos(focus.col, focus.row - 1); AdjustSelection
- ELSIF (keysym = 0FF54H) & (focus.row < nofRowsC - 1) THEN SetFocusPos(focus.col, focus.row + 1); AdjustSelection
- END
- END KeyEvent;
- PROCEDURE Scrolled(sender, data : ANY);
- BEGIN
- IF ~IsCallFromSequencer() THEN sequencer.ScheduleEvent(SELF.Scrolled, sender, data)
- ELSE
- SetTopPosition(scrollx.pos.Get(), scrolly.pos.Get(), FALSE);
- AlignSubComponents
- END
- END Scrolled;
- PROCEDURE SetHighlight(col, row : LONGINT);
- VAR or, nr, cr : WMRectangles.Rectangle;
- BEGIN
- Acquire;
- IF (col = highlight.col) & (row = highlight.row)
- OR (selectionMode IN {GridSelectSingleCol, GridSelectCols}) & (col = highlight.col)
- OR (selectionMode IN {GridSelectSingleRow, GridSelectRows}) & (row = highlight.row)
- THEN Release; RETURN
- END;
- CASE selectionMode OF
- | GridSelectSingleCol, GridSelectCols : nr := GetVisibleColRect(col); or := GetVisibleColRect(highlight.col)
- | GridSelectSingleRow, GridSelectRows : nr := GetVisibleRowRect(row); or := GetVisibleRowRect(highlight.row)
- ELSE
- or := GetVisibleCellRect(highlight.col, highlight.row);
- nr := GetVisibleCellRect(col, row);
- END;
- highlight.col := col; highlight.row := row;
- cr := or; WMRectangles.ExtendRect(cr, nr);
- IF WMRectangles.Area(or) + WMRectangles.Area(nr) < WMRectangles.Area(cr) THEN InvalidateRect(or); InvalidateRect(nr)
- ELSE InvalidateRect(cr)
- END;
- Release
- END SetHighlight;
- PROCEDURE GetVisibleColRect(col : LONGINT) : WMRectangles.Rectangle;
- VAR r : WMRectangles.Rectangle;
- BEGIN
- r := GetVisibleCellRect(col, tableStart.row);
- r.t := 0; r.b := bounds.GetHeight();
- RETURN r
- END GetVisibleColRect;
- PROCEDURE GetVisibleRowRect(row: LONGINT) : WMRectangles.Rectangle;
- VAR r : WMRectangles.Rectangle;
- BEGIN
- r := GetVisibleCellRect(tableStart.col, row);
- r.l := 0; r.r := bounds.GetWidth();
- RETURN r
- END GetVisibleRowRect;
- PROCEDURE SetSelection*(scol, srow, ecol, erow : LONGINT);
- VAR or, nr, cr : WMRectangles.Rectangle; done : BOOLEAN;
- oldStart, oldEnd : CellPos;
- BEGIN
- Acquire;
- oldStart := selStart; oldEnd := selEnd;
- selStart.col := Strings.Min(scol, ecol); selStart.row := Strings.Min(srow, erow);
- selEnd.col := Strings.Max(scol, ecol); selEnd.row := Strings.Max(srow, erow);
- IF (oldStart.col = selStart.col) & (oldStart.row= selStart.row) &
- (oldEnd.col = selEnd.col) & (oldEnd.row= selEnd.row) THEN
- Release;
- RETURN
- END;
- done := FALSE;
- CASE selectionMode OF
- | GridSelectSingleCell :
- or := GetVisibleCellRect(oldStart.col, oldStart.row); nr := GetVisibleCellRect(selStart.col, selStart.row)
- | GridSelectSingleCol : or := GetVisibleColRect(oldStart.col); nr := GetVisibleColRect(selStart.col)
- | GridSelectSingleRow : or := GetVisibleRowRect(oldStart.row); nr := GetVisibleRowRect(selStart.row)
- ELSE
- Invalidate(); done := TRUE
- END;
- IF ~done THEN
- cr := or; WMRectangles.ExtendRect(cr, nr);
- IF WMRectangles.Area(or) + WMRectangles.Area(nr) < WMRectangles.Area(cr) THEN InvalidateRect(or); InvalidateRect(nr)
- ELSE InvalidateRect(cr)
- END;
- END;
- Release;
- onSelect.Call(NIL)
- END SetSelection;
- (** must be interpreted according to SelectionMode *)
- PROCEDURE GetSelection*(VAR scol, srow, ecol, erow : LONGINT);
- BEGIN
- Acquire;
- scol := selStart.col; srow := selStart.row;
- ecol := selEnd.col; erow := selEnd.row;
- Release
- END GetSelection;
- PROCEDURE OnFixedXGridLine(x, y : LONGINT; VAR xCell, pos : LONGINT) : BOOLEAN;
- VAR ty, tx : LONGINT;
- PROCEDURE Find(startX, endX, startCol, endCol : LONGINT; VAR col, xPos : LONGINT) : BOOLEAN;
- VAR cw : LONGINT;
- BEGIN
- col := startCol; xPos := startX;
- REPEAT
- cw := GetColWidth(col);
- IF ABS(xPos + cw + cellDistC - x) < PixelRange THEN RETURN TRUE END;
- xPos := xPos + cw + cellDistC; INC(col);
- UNTIL (col >= endCol) OR (xPos >= endX);
- RETURN FALSE
- END Find;
- BEGIN
- GetFixedPixels(tx, ty);
- IF (x < tx) & (y < ty) OR (x < tx) THEN (* column fixed *)
- RETURN Find(0, x + PixelRange, 0, fixedColsC, xCell, pos)
- ELSIF (y < ty) THEN (* row fixed *)
- RETURN Find(tx, x + PixelRange, tableStart.col, nofColsC, xCell, pos)
- ELSE (* normal cells *)
- RETURN FALSE
- END
- END OnFixedXGridLine;
- PROCEDURE OnFixedYGridLine(x, y : LONGINT; VAR yCell, pos : LONGINT) : BOOLEAN;
- VAR ty, tx : LONGINT;
- PROCEDURE Find(startY, endY, startRow, endRow : LONGINT; VAR row, yPos : LONGINT) : BOOLEAN;
- VAR ch : LONGINT;
- BEGIN
- row := startRow; yPos := startY;
- REPEAT
- ch := GetRowHeight(row);
- IF ABS(yPos + ch + cellDistC - y) < PixelRange THEN RETURN TRUE END;
- yPos := yPos + ch + cellDistC; INC(row);
- UNTIL (row >= endRow) OR (yPos >= endY);
- RETURN FALSE
- END Find;
- BEGIN
- GetFixedPixels(tx, ty);
- IF (y < ty) THEN (* column fixed *)
- RETURN Find(0, y + PixelRange, 0, fixedRowsC, yCell, pos)
- ELSIF (x < tx) THEN (* row fixed *)
- RETURN Find(ty, y + PixelRange, tableStart.row, nofRowsC, yCell, pos)
- ELSE (* normal cells *)
- RETURN FALSE
- END
- END OnFixedYGridLine;
- PROCEDURE PointerDown(x, y : LONGINT; keys : SET); (** PROTECTED *)
- VAR col, row : LONGINT; state : SET;
- BEGIN
- PointerDown^(x, y, keys);
- lastkeys := keys;
- IF keys * {0,1} # {} THEN
- IF allowColResize.Get() & (colWidths # NIL) & OnFixedXGridLine(x, y, dragCellSpacingNr, dragCellSpacingPos) THEN
- dragCellSpacingWidth := TRUE;
- ELSIF allowRowResize.Get() & (rowHeights # NIL) & OnFixedYGridLine(x, y, dragCellSpacingNr, dragCellSpacingPos) THEN
- dragCellSpacingHeight := TRUE;
- ELSE
- FindCellXY(x, y, col, row);
- state := GetCellState(col, row);
- wasSelected := CellSelected IN state;
- IF shiftDown & (0 IN keys) THEN
- SetSelection(selA.col, selA.row, col, row);
- dragPossible := FALSE; selecting := TRUE
- ELSE
- IF CellSelected IN state THEN selecting := FALSE; dragPossible := TRUE; downX := x; downY := y
- ELSE
- dragPossible := FALSE; selecting := TRUE;
- selA.col := col; selA.row := row; SetFocusPos(col, row);
- SetSelection(col, row, col, row)
- END
- END
- END
- END
- END PointerDown;
- PROCEDURE PointerLeave;
- BEGIN
- SetHighlight(-1, -1); pointerInside := FALSE
- END PointerLeave;
- PROCEDURE PointerMove(x, y : LONGINT; keys : SET); (** PROTECTED *)
- VAR col, row : LONGINT; manager : WM.WindowManager; cell, pos : LONGINT;
- BEGIN
- IF dragCellSpacingWidth THEN
- x := Strings.Min(x, bounds.GetWidth());
- IF (colWidths # NIL) & (dragCellSpacingNr < LEN(colWidths)) THEN
- colWidths[dragCellSpacingNr] := Strings.Max(x - dragCellSpacingPos, 1);
- Invalidate()
- END;
- ELSIF dragCellSpacingHeight THEN
- y := Strings.Min(y, bounds.GetHeight());
- IF (rowHeights # NIL) & (dragCellSpacingNr < LEN(rowHeights)) THEN
- rowHeights[dragCellSpacingNr] := Strings.Max(y - dragCellSpacingPos, 1);
- Invalidate()
- END;
- ELSIF dragPossible THEN
- IF (ABS(x - downX) > DragDist) OR (ABS(y - downY) > DragDist) THEN
- dragPossible := FALSE;
- drag := TRUE;
- AutoStartDrag
- END
- ELSE
- FindCellXY(x, y, col, row); pointerInside := TRUE; lastPointerX := x; lastPointerY := y;
- IF allowColResize.Get() & (colWidths # NIL) & OnFixedXGridLine(x, y, cell, pos) THEN
- IF ~hasOldPointer THEN
- prevPointerInfo := GetPointerInfo();
- hasOldPointer := TRUE;
- manager := WM.GetDefaultManager();
- SetPointerInfo(manager.pointerLeftRight)
- END;
- ELSIF allowRowResize.Get() & (rowHeights # NIL) & OnFixedYGridLine(x, y, cell, pos) THEN
- IF ~hasOldPointer THEN
- prevPointerInfo := GetPointerInfo();
- hasOldPointer := TRUE;
- manager := WM.GetDefaultManager();
- SetPointerInfo(manager.pointerUpDown)
- END;
- ELSE
- IF hasOldPointer THEN SetPointerInfo(prevPointerInfo); hasOldPointer := FALSE END;
- END;
- IF selecting THEN
- IF 0 IN keys THEN
- CASE selectionMode OF
- | GridSelectSingleCell, GridSelectSingleCol, GridSelectSingleRow : SetSelection(col, row, col, row)
- | GridSelectCols, GridSelectRows, GridSelectBlock, GridSelectHorizontal, GridSelectVertical:
- SetSelection(selA.col, selA.row, col, row)
- ELSE
- END;
- SetFocusPos(col, row)
- END
- END;
- IF selectOnPointerOver THEN SetSelection(col, row, col, row) END;
- SetHighlight(col, row)
- END;
- IF keys = {} THEN dragPossible := FALSE; selecting := FALSE END
- END PointerMove;
- PROCEDURE CellClicked*(col, row : LONGINT); (** PROTECTED *)
- BEGIN
- IF wasSelected & onClickSelected.HasListeners() THEN
- dragPossible := FALSE;
- onClickSelected.Call(GetCellData(col, row))
- END;
- IF onClick.HasListeners() THEN
- onClick.Call(GetCellData(col, row))
- END
- END CellClicked;
- PROCEDURE PointerUp(x, y : LONGINT; keys : SET); (** PROTECTED *)
- VAR col, row : LONGINT; d : BOOLEAN;
- BEGIN
- IF 2 IN lastkeys THEN lastkeys := keys; RETURN END;
- d := dragCellSpacingWidth OR dragCellSpacingHeight OR
- (selecting & (selStart.row # selEnd.row) OR (selStart.col # selEnd.col));
- IF ~d THEN
- FindCellXY(x, y, col, row);
- SetSelection(col, row, col, row); SetFocusPos(col, row);
- IF ~drag THEN CellClicked(col, row) END
- END;
- drag := FALSE;
- dragCellSpacingWidth := FALSE; dragCellSpacingHeight := FALSE;
- selecting := FALSE
- END PointerUp;
- PROCEDURE WheelMove*(dz: LONGINT); (** PROTECTED *)
- VAR t, l : LONGINT;
- BEGIN
- GetTopPosition(l, t); t := t + dz; SetTopPosition(l, t, TRUE)
- END WheelMove;
- END GenericGrid;
- VAR
- GSonSelect, GSonClick, GSonClickSelected,
- GSonSelectInfo, GSonClickInfo, GSonClickSelectedInfo: String;
- GSGenericGrid : String;
- fixedColsProto, fixedRowsProto : WMProperties.Int32Property;
- defaultColWidthProto, defaultRowHeightProto : WMProperties.Int32Property;
- allowColResizeProto, allowRowResizeProto, adjustFocusPositionProto : WMProperties.BooleanProperty;
- nofColsProto, nofRowsProto, cellDistProto : WMProperties.Int32Property;
- showScrollXProto, showScrollYProto, alwaysShowScrollXProto, alwaysShowScrollYProto : WMProperties.BooleanProperty;
- PROCEDURE Init;
- BEGIN
- GSonSelect := NewString("onSelect");
- GSonClick := NewString("onClick");
- GSonClickSelected := NewString("onClickSelected");
- GSonSelectInfo := NewString("Is called when a cell is selected");
- GSonClickInfo := NewString("is called on a click");
- GSonClickSelectedInfo := NewString("is called when a selected cell is clicked");
- GSGenericGrid := NewString("GenericGrid");
- END Init;
- PROCEDURE InitProto;
- BEGIN
- NEW(fixedColsProto, NIL, NewString("fixedCols"), NewString("number of fixed columns"));
- NEW(fixedRowsProto, NIL, NewString("fixedRows"), NewString("number of fixed rows"));
- NEW(defaultColWidthProto, NIL, NewString("defaultColWidth"), NewString("default width of a column"));
- NEW(defaultRowHeightProto, NIL, NewString("defaultRowHeight"), NewString("default height of a row"));
- defaultColWidthProto.Set(100); defaultRowHeightProto.Set(20);
- NEW(allowColResizeProto, NIL, NewString("allowColResize"), NewString("can columns be resized"));
- allowColResizeProto.Set(TRUE);
- NEW(allowRowResizeProto, NIL, NewString("allowRowResize"), NewString("can rows be resized"));
- allowRowResizeProto.Set(TRUE);
- NEW(adjustFocusPositionProto, NIL, NewString("adjustFocusPosition"), NewString("focus adjusting when clicking/dragging cells"));
- adjustFocusPositionProto.Set(TRUE);
- NEW(nofColsProto, NIL, NewString("nofCols"), NewString("number of columns in the table"));
- nofColsProto.Set(1);
- NEW(nofRowsProto, NIL, NewString("nofRows"), NewString("number of rows in the table"));
- nofRowsProto.Set(1);
- NEW(cellDistProto, NIL, NewString("cellDist"), NewString("distance between cells"));
- cellDistProto.Set(1);
- NEW(showScrollXProto, NIL, NewString("showScrollX"), NewString("horizontal scrollbar is displayed if needed"));
- showScrollXProto.Set(TRUE);
- NEW(showScrollYProto, NIL, NewString("showScrollY"), NewString("vertical scrollbar is displayed if needed"));
- showScrollYProto.Set(TRUE);
- NEW(alwaysShowScrollXProto, NIL, NewString("alwaysShowScrollX"), NewString("horizontal scrollbar is always displayed"));
- NEW(alwaysShowScrollYProto, NIL, NewString("alwaysShowScrollY"), NewString("vertical scrollbar is always displayed"));
- END InitProto;
- PROCEDURE GenGrid*() : XML.Element;
- VAR grid : GenericGrid;
- BEGIN
- NEW(grid);
- RETURN grid
- END GenGrid;
- PROCEDURE NewString*(CONST x : ARRAY OF CHAR) : String;
- BEGIN
- RETURN Strings.NewString(x)
- END NewString;
- BEGIN
- Init;
- InitProto;
- END WMGrids.
- SystemTools.Free WMGrids ~
- History:
- 03.04.2006 Added AlignSubComponents in last line for GenericGrid.RecacheAllProperties
|