Page 3 of 3

xGrid Code Release!

Posted: Sun Oct 23, 2005 7:27 pm
by Xombie
Weekend madness :D

I just got back from vacation and thought I'd share my sense of happiness at being back in a really nice familiar place ^_^

Here is the current (very uncompleted) code for xGrid. I haven't even gotten the cell formatting finished in the demo app so it'd be best if you just dropped xGrid.pb into your own app and tested it. I'll continue updating as I can. Still a lot to add and I DO plan on adding to it so please don't think it just died.

Here are some code snippets from a couple parts.

Code: Select all

;{ Header Text and Cell Dividing Lines
      lPen = CreatePen_(#PS_SOLID, 1, RGB(128, 128, 128))
      ; Create the pen to draw the dividing lines.
      SelectObject_(HandleImage, lPen)
      ; Select the pen for usage.
      SetTextColor_(HandleImage, RGB(0, 0, 0)) : SetBkMode_(HandleImage, #TRANSPARENT)
      ; Set text properties.  Black text.
      HoldHeight = -Int((10 * GetDeviceCaps_(HandleImage, #LOGPIXELSY)) / 72)
      ; Convert the height to pixels.
      CellFont = CreateFont_(HoldHeight,0,0,0,0,0,0,0,0,0,0,0,0,"Arial")
      ; Create the font we'll use to draw the text in the headers.
      SelectObject_(HandleImage, CellFont)
      ; And select it for use.
      ;/ Column Text.
      xg_CellRectFromLocation(*xGrid, *xGrid\CellBoundaries\Left, -1, @TempRect)
      ; Store the rectangular dimensions of the leftmost column.
      If *xGrid\Arrays\ColumnWidth : HoldSize = MemorySize(*xGrid\Arrays\ColumnWidth) : EndIf
      ; Only need to call this once for column drawing so store the size of the column width array if it exists.
      For LoopColumn = *xGrid\CellBoundaries\Left To *xGrid\CellBoundaries\Right
         ; Loop through the visible columns.
         CaughtColumn = #False
         ; This will be True if a custom width exists for the next column.  False if using the default width.
         If LoopColumn > 25 : CellText = Chr(65 + Int(LoopColumn / 26) - 1)+Chr(65 + (LoopColumn - (26 * Int(LoopColumn / 26)))) : Else : CellText = Chr(65 + LoopColumn) : EndIf
         ; Store the column header.  Handle any double characters "AA", "AB", etc...
         If TempRect\Right < *xGrid\Width + *xGrid\OffsetPosition\X : MoveToEx_(HandleImage,TempRect\Right - *xGrid\OffsetPosition\X, 0, 0) : LineTo_(HandleImage, TempRect\Right - *xGrid\OffsetPosition\X, *xGrid\Height) : EndIf
         ; We're only drawing right cell boundaries for the columns so no need to draw it if it's beyond our viewable area.
         DrawText_(HandleImage, @CellText, Len(CellText), @HoldRect, #DT_NOCLIP | #DT_NOPREFIX | #DT_SINGLELINE | #DT_CALCRECT) 
         ; Calculate the width and height needed for the text.
         TextPosition\X = TempRect\Left + Int(((TempRect\Right - TempRect\Left) - HoldRect\Right) / 2) - *xGrid\OffsetPosition\X
         TextPosition\Y = TempRect\Top + Int(((TempRect\Bottom - TempRect\Top) - HoldRect\Bottom) / 2)
         ; Store the centered text coordinates.
         MoveToEx_(HandleImage, TextPosition\X, TextPosition\Y, 0)
         ; Move our drawing cursor to the center of the cell.
         If TextPosition\X < *xGrid\OffsetPosition\X + *xGrid\HeaderWidth
            ; Text intersects row number column.  Clip it.
            HandleClip = CreateRectRgn_(*xGrid\HeaderWidth, 0, TempRect\Right - *xGrid\OffsetPosition\X, *xGrid\HeaderHeight)
            SelectClipRgn_(HandleImage, HandleClip)
            ;
         ElseIf TempRect\Bottom - TempRect\Top < HoldRect\Bottom Or TempRect\Right - TempRect\Left < HoldRect\Right
            ; Text is wider than width of the cell.  Clip it.
            HandleClip = CreateRectRgn_(TempRect\Left - *xGrid\OffsetPosition\X, TempRect\Top - *xGrid\OffsetPosition\Y, TempRect\Right - *xGrid\OffsetPosition\X, TempRect\Bottom - *xGrid\OffsetPosition\Y)
            SelectClipRgn_(HandleImage, HandleClip)
            ;
         EndIf
         ;
         DrawText_(HandleImage, @CellText, Len(CellText), @HoldRect, #DT_NOCLIP | #DT_NOPREFIX | #DT_SINGLELINE)
         ; Draw the column header text.
         If HandleClip : SelectClipRgn_(HandleImage, 0) : DeleteObject_(HandleClip) : HandleClip = 0 : EndIf
         ;
         If LoopColumn = *xGrid\MaxColumns : Break : EndIf
         ; Break when we've reached the last column.
         TempRect\Left = TempRect\Right
         ; The next column's left boundary is the right boundary of the current column.
         If *xGrid\Arrays\ColumnWidth
            ;
            *Position = *xGrid\Arrays\ColumnWidth
            ;
            While *Position - *xGrid\Arrays\ColumnWidth < HoldSize
               ;
               If PeekL(*Position) = *xGrid\ActiveSheet And PeekL(*Position + 4) = LoopColumn + 1
                  ; Found a custom width for the next column.
                  TempRect\Right = TempRect\Left + PeekL(*Position + 8)
                  ; Set the next right boundary location.
                  CaughtColumn = #True
                  ;
                  Break
                  ; Exit our loop.
               EndIf
               ;
               *Position + 12
               ;
            Wend
            ;
            If CaughtColumn = #False : TempRect\Right = TempRect\Left + #xGrid_DefaultCellWidth : EndIf
            ; If no custom width exists for the next column, use the default cell width.
         Else
            ; No custom widths exist.
            TempRect\Right = TempRect\Left + #xGrid_DefaultCellWidth
            ; Set cell dimensions to the next column.
         EndIf
         ;
      Next LoopColumn
      ;
      GreyArea\X = TempRect\Right
      ; Store the right value of the last column drawn.  We'll use this to check if the non-editable area is visible.
This bit of code draws the column header text.

Code: Select all

   If Message = #WM_KEYDOWN Or Message = #WM_KEYUP Or Message = #WM_CHAR Or Message = #WM_COMMAND
      ; Only need to call this code once for the three messages.
      If _xGrid_Focused
         ; Make sure we have a valid grid handle stored.  If not, a grid is not focused.
         HoldSize = MemorySize(_xGrid_List)
         ;
         *Position = _xGrid_List
         ;
         While *Position - _xGrid_List < HoldSize
            ;
            If PeekL(*Position + 8) = _xGrid_Focused : *xGrid = PeekL(*Position) : Break : EndIf
            ;
            *Position + 12
            ;
         Wend
         ;
         If *xGrid
            ;
            xg_LastGoodCell(*xGrid, @rGrid, #True)
            ; Call the last good cell function simply to find the top left most cell and the bottom right most cell.  We'll use this
            ; to determine the new rectangular range to select.
            If rGrid\Left = rGrid\Right And rGrid\Top = rGrid\Bottom
               ; Only one cell is selected.
               HoldPosition\X = rGrid\Left : HoldPosition\Y = rGrid\Top
               ;
            Else
               ; Multiple cells are selected.
               If rGrid\Left < *xGrid\MouseDownSelectedCell\X
                  ;
                  If rGrid\Top < *xGrid\MouseDownSelectedCell\Y
                     HoldPosition\X = rGrid\Left : HoldPosition\Y = rGrid\Top
                  Else
                     HoldPosition\X = rGrid\Left : HoldPosition\Y = rGrid\Bottom
                  EndIf
                  ;
               Else
                  ;
                  If rGrid\Top < *xGrid\MouseDownSelectedCell\Y
                     HoldPosition\X = rGrid\Right : HoldPosition\Y = rGrid\Top
                  Else
                     HoldPosition\X = rGrid\Right : HoldPosition\Y = rGrid\Bottom
                  EndIf
                  ;
               EndIf
               ;
            EndIf
            ;
         EndIf
         ;
      EndIf
      ;
   EndIf
   ;
This code fragment determines the last selected cell in a cell block - used for moving around in the cell with the cursor keys.

Code: Select all

Procedure.l xg_PointerFromNumber(GadgetNumber.l)
   ;
   *Position = _xGrid_List
   ;
   HoldSize = MemorySize(_xGrid_List)
   ;
   While *Position - _xGrid_List < HoldSize
      ;
      If PeekL(*Position + 4) = GadgetNumber : ProcedureReturn PeekL(*Position) : EndIf
      ;
      *Position + 12
      ;
   Wend
   ;
   ProcedureReturn 0
   ;
EndProcedure
Finally, return the handle of the xGrid object based on it's PB 'gadget' number. I store information like this all in memory - no linked lists.

Hummm... well, mainly I just want to put this out there for people to test it in their own projects while I update stuff. It's still buggy and a lot of things are missing so I wouldn't recommend using it in a major-ish project just yet ^_^

Have fun with it and remember - credit where credit is due, please.

Download here: http://www.seijin.net/Storage/xGrid-Code.rar

EDIT:

Forgot to mention something. In the following week I will add (in no particular order) - formula support, copy/pasting, simple save/open (as time permits), column/row insertion/deletion, sheet deletion, optimizations, optimizations and optimizations :D

So please, don't post code bits you've modified as I'm still in the process of ironing out my own 'official' version ^_^

Posted: Sun Oct 23, 2005 8:09 pm
by blueznl
may have some good use for this... waiting to see what you come up with next :-)