April 29, 2024, 10:51:15 AM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Grid control in development

Started by Ionic Wind Support Team, October 16, 2006, 02:14:28 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Ionic Wind Support Team

I've been working on a general purpose grid control for Aurora, and possibly other languages if I package it in a DLL.  Havent decided yet if I'll just give it away or perhaps charge $5 with source included. 

I will post new screen shots and examples as I continue with its development. 

The image below was created with this code:


sub main()
{
CGridWnd grid;
grid.Create(0,0,640,480,AWS_VISIBLE|AWS_SYSMENU|AWS_BORDER|AWS_CAPTION|AWS_SIZE,0,"Grid Test",0);
grid.SetGridSize(10,10);
for(int x=1;x<11;x++)
{
grid.SetHeaderText(1,x,NumToStr(x));
grid.SetHeaderText(0,x,ToChar('A'-1+x));
}
grid.SetCellText(1,1,"Test");
grid.SetCellText(2,1,"Test2");
grid.SetCellText(10,10,"Last Cell\nA multi line one",DT_WORD_ELLIPSIS);
grid.SetCellColor(1,1,RGB(255,0,0),RGB(255,255,255));
grid.SetCellColor(2,1,RGB(255,255,255),RGB(0,0,192));
grid.SetCellColor(10,10,0,RGB(255,207,0));
grid.SetRowHeight(10,40);
grid.SetColumnWidth(10,100);
while grid.IsValid() { wait(); }
}


Ionic Wind Support Team


J B Wood (Zumwalt)


Ionic Wind Support Team

Quote from: zumwalt on October 16, 2006, 06:54:16 AM
What is this based on?

All Aurora code from scratch.  Tested on 98 - XP for consistancy of drawing.

Quote from: kale
This will maybe help:


Yes I know about Sapero's efforts on converting that code.  And it is a fine job.  The PellesC grid needs a few more features and I didn't want to step on his code.

I also wanted a grid control that had a bit more automation, with the ability to link with the database classes, a definitive serialization format, etc.

Paul.
Ionic Wind Support Team

J B Wood (Zumwalt)


Bruce Peaslee

Neat. If you decide to give it away, does that mean you would add the control to Aurora or just distribute the code?
Bruce Peaslee
"Born too loose."
iTired (There's a nap for that.)
Well, I headed for Las Vegas
Only made it out to Needles

Steven Picard

I will be needing a grid for Aurora very soon.  I was going to use Sapero's but what's the estimated date of completion for this one?  No rush, I'd rather see something bug free and feature rich than rushed.  ;D

Ionic Wind Support Team

Probably a week to finish the base code. 

Ionic Wind Support Team

Ionic Wind Support Team

Still working on the grid. Inplace editing is done, font control is done, and boolean cells are now supported.  The grid control can be used two ways.  #1) By deriving a new class and overriding handlers, or #2)  by using it as a normal control and using OnControl and OnNotify in the parent window.

Paul.
Ionic Wind Support Team

Haim


Ionic Wind Support Team

Here is the current source of the grid control.  I will be including it with Aurora as part of the installation, still needs some work yet.


//Aurora Grid Control class
//(c) 2006 Paul Turley
//Reproduction without permission prohibited.

#define HDS_HORZ                0x0000
#define HDS_BUTTONS             0x0002
#define HDS_HOTTRACK            0x0004
#define HDS_HIDDEN              0x0008
#define HDS_DRAGDROP            0x0040
#define HDS_FULLDRAG            0x0080
#define HDS_FILTERBAR           0x0100
#define HDS_FLAT                0x0200
#define HDM_FIRST               0x1200
#define HDM_LAYOUT              (HDM_FIRST + 5)
//our own custom notification message, sized to word so we can use WM_COMMAND instead of WM_NOTIFY
#define HDN_TRACKDONE (HDN_FIRST - 99) & 0xFFFF

#define WM_COMMAND                      0x0111
#define WM_NOTIFY                       0x004E
#define WM_GETFONT 0x31

/* flags for DrawFrameControl */

#define DFC_CAPTION             1
#define DFC_MENU                2
#define DFC_SCROLL              3
#define DFC_BUTTON              4
#define DFC_POPUPMENU           5

#define DFCS_CAPTIONCLOSE       0x0000
#define DFCS_CAPTIONMIN         0x0001
#define DFCS_CAPTIONMAX         0x0002
#define DFCS_CAPTIONRESTORE     0x0003
#define DFCS_CAPTIONHELP        0x0004

#define DFCS_MENUARROW          0x0000
#define DFCS_MENUCHECK          0x0001
#define DFCS_MENUBULLET         0x0002
#define DFCS_MENUARROWRIGHT     0x0004
#define DFCS_SCROLLUP           0x0000
#define DFCS_SCROLLDOWN         0x0001
#define DFCS_SCROLLLEFT         0x0002
#define DFCS_SCROLLRIGHT        0x0003
#define DFCS_SCROLLCOMBOBOX     0x0005
#define DFCS_SCROLLSIZEGRIP     0x0008
#define DFCS_SCROLLSIZEGRIPRIGHT 0x0010

#define DFCS_BUTTONCHECK        0x0000
#define DFCS_BUTTONRADIOIMAGE   0x0001
#define DFCS_BUTTONRADIOMASK    0x0002
#define DFCS_BUTTONRADIO        0x0004
#define DFCS_BUTTON3STATE       0x0008
#define DFCS_BUTTONPUSH         0x0010

#define DFCS_INACTIVE           0x0100
#define DFCS_PUSHED             0x0200
#define DFCS_CHECKED            0x0400

#define DFCS_TRANSPARENT        0x0800
#define DFCS_HOT                0x1000

#define DFCS_ADJUSTRECT         0x2000
#define DFCS_FLAT               0x4000
#define DFCS_MONO               0x8000

#define DT_TOP              0x00000000
#define DT_LEFT             0x00000000
#define DT_CENTER           0x00000001
#define DT_RIGHT            0x00000002
#define DT_VCENTER          0x00000004
#define DT_BOTTOM           0x00000008
#define DT_WORDBREAK        0x00000010
#define DT_SINGLELINE       0x00000020
#define DT_EXPANDTABS       0x00000040
#define DT_TABSTOP          0x00000080
#define DT_NOCLIP           0x00000100
#define DT_EXTERNALLEADING  0x00000200
#define DT_CALCRECT         0x00000400
#define DT_NOPREFIX         0x00000800
#define DT_INTERNAL         0x00001000

#define DT_EDITCONTROL      0x00002000
#define DT_PATH_ELLIPSIS    0x00004000
#define DT_END_ELLIPSIS     0x00008000
#define DT_MODIFYSTRING     0x00010000
#define DT_RTLREADING       0x00020000
#define DT_WORD_ELLIPSIS    0x00040000

#define OCR_SIZEWE          32644
#define OCR_SIZENS          32645
#define OCR_IBEAM           32513

struct WINDOWPOS
{
    unsigned int hwnd;
    unsigned int hwndInsertAfter;
    int          x;
    int          y;
    int          cx;
    int          cy;
    unsigned int flags;
}

struct HDLAYOUT
{
    RECT *prc;
    WINDOWPOS *pwpos;
}

struct NMHDR
{
    unsigned int hwndFrom;
    unsigned int idFrom;
    unsigned int code;
}

declare import,SendMessage alias "SendMessageA" (unsigned int hWnd, unsigned int uMsg, unsigned int wParam, unsigned int lParam), unsigned int;
declare import,PostMessage alias "PostMessageA" (unsigned int hWnd, unsigned int uMsg, unsigned int wParam, unsigned int lParam), unsigned int;

declare import,DrawFrameControl(
  UINT hdc,     // handle to device context
  RECT *lprc, // bounding rectangle
  UINT uType,  // frame-control type
  UINT uState  // frame-control state
),int;

declare import, DrawText alias "DrawTextA"(
  UINT hDC,          // handle to DC
  STRING *lpString, // text to draw
  int nCount,       // text length
  RECT *lpRect,    // formatting dimensions
  UINT uFormat      // text-drawing options
),int;

declare import,SetTextAlign(
  UINT hdc,     // handle to DC
  UINT fMode   // text-alignment option
),UINT;

declare import,InvalidateRect(unsigned int hWnd, pointer lprc, int bErase), int;

declare import,PtInRect(
  RECT *lprc,  // rectangle
  POINT pt BYVAL  // point
),int;

declare import,InflateRect(
RECT *lprc, // address of rectangle
int dx, // amount to increase or decrease width
int dy  // amount to increase or decrease height
),int; 

declare import, SetCapture(uint hwnd),uint;
declare import, ReleaseCapture(),int;
declare import, SetWindowLongA(uint hwnd,int nIndex,uint value),INT;
declare import, SelectObject(unsigned int hdc, unsigned int hdiobj), unsigned int;

declare extern InitializeControl(CControl *control,int type);

//hit testing return values
#define HIT_NOWHERE 0
#define HIT_LEFT_RESIZE 1
#define HIT_CELL 2
#define HIT_LEFT_BUTTON 4

//Cell types
#define CELL_TEXT 0x0001
#define CELL_IMAGE 0x0002
#define CELL_CHECKBOX 0x0003

class gridCell
{
declare gridCell();
string m_strText;
uint m_cForeColor;
uint m_cBackColor;
uint m_uStyle;
uint m_uType;
int m_bReadOnly;
}

class CGridWnd : CControl
{
declare CGridWnd();
declare _CGridWnd();
declare virtual Create(int l,int t,int w,int h,int style,int nID,string title,CWindow *parent),int;
declare virtual OnClose(),int;
declare virtual OnHScroll(int nCommand,int nPos,int nID),int;
declare virtual OnLButtonDblClk(int x,int y,int flags),int;
declare virtual OnLButtonDown(int x,int y, int flags),int;
declare virtual OnLButtonUp(int x,int y,int flags),int;
declare virtual OnMouseMove(int x,int y,int flags),int;
declare virtual OnPaint(),int;
declare virtual OnRButtonUp(int x,int y,int flags),int;
declare virtual OnVScroll(int nCommand,int nPos,int nID),int;
declare virtual OnSize(int nType,int cx,int cy),int;
declare virtual OnControl(int nID, int nNotifyCode, unsigned int hControl),int;
declare HitTest(int x,int y,opt int *item = NULL),int;
// operations
public:
declare SetGridSize(uint x,uint y),int;
declare AddRow(),int;
declare SetCellText(uint x,uint y,string text,opt uint format = DT_VCENTER);
declare SetCellColor(uint x,uint y,uint fg,uint bg);
declare SetCellType(uint x,uint y,uint type);
declare SetHeaderText(int header,int iItem,string text);
declare SetRowHeight(int iRow,int Height);
declare SetColumnWidth(int iColumn,int Width);
declare SetDefaultFont(string typeface,int height,int weight,OPT int flags=0);
declare SetHeaderFont(string typeface,int height,int weight,OPT int flags=0);
declare ShowGridLines(int bShow);
CEdit m_cellEdit;
protected:
declare CalculateRects();
CHeaderCtrl *m_topHeader;
CHeaderCtrl *m_LeftHeader;
pointer *m_gridArray;
RECT *m_gridRects;
int m_nTopWidth;
uint m_nCountX;
uint m_nCountY;
uint m_hNSCursor;
uint m_hIBeamCursor;
int m_bDragLeft;
int m_nDragItem;
int m_nDragStartY;
int m_nDragLastY;
int m_bEditShown;
int m_nEditItem;
int m_bShowGridLines;
//fonts
string m_strDefaultFont;
int m_nDefaultFontSize;
int m_nDefaultFontWeight;
string m_strHeaderFont;
int m_nHeaderFontSize;
int m_nHeaderFontWeight;
uint m_hHeaderFont;

}

//gridCell Implementation
gridCell::gridCell()
{
m_strText = "";
m_cForeColor = 0;
m_cBackColor = 0xFFFFFF;
m_uStyle = DT_VCENTER | DT_SINGLELINE;
m_bReadOnly = false;
m_uType = CELL_TEXT;
}

//CGridWnd Implementation
CGridWnd::CGridWnd()
{
m_topHeader = NULL;
m_leftHeader = NULL;
m_nTopWidth = 0;
m_gridArray = NULL;
m_gridRects = NULL;
CCursor c;
c.LoadOEMCursor(OCR_SIZENS);
m_hNSCursor = c.Detach();
c.LoadOEMCursor(OCR_IBEAM);
m_hIBeamCursor = c.Detach();
m_bDragLeft = false;
m_nDragItem = 0;
m_nDragStartY = 0;
m_nDragLastY = 0;
m_bEditshown = false;
m_nEditItem = 0;
m_bShowGridLines = true;

m_strDefaultFont = "Verdana";
m_nDefaultFontSize = 10;
m_nDefaultFontWeight = 400;

m_strHeaderFont = "Verdana";
m_nHeaderFontSize = 10;
m_nHeaderFontWeight = 700;
m_nCountX = 0;
m_nCountY = 0;

}

CGridWnd::_CGridWnd()
{
if(m_topHeader)
delete m_topHeader;
if(m_leftHeader)
delete m_leftHeader;
int count = m_nCountX * m_nCountY;
//sanity checks
if(m_gridArray)
{
for(int z = 0;z<count;z++)
{
gridCell *temp = *m_gridArray[z];
delete temp;
}
delete m_gridArray;
}
if(m_gridRects)
delete m_gridRects;
}

CGridWnd::Create(int l,int t,int w,int h,int style,int nID,string title,CWindow *parent),int
{

int nReturn = CWindow!!Create(l,t,w,h,style,0,title,parent);
RECT rc = GetClientRect();
HDLAYOUT hdl;
WINDOWPOS wp;
hdl.prc = &rc;
hdl.pwpos = &wp;

if(1)
{
m_TopHeader = new(CHeaderCtrl,1);
m_TopHeader->Create(0,0,0,0,0x02|ACCS_TOP,9998,"",this);
SendMessage(m_topHeader->GetHandle(),HDM_LAYOUT,0,&hdl);
m_TopHeader->SetSize(wp.x,wp.y,wp.cx,wp.cy);
m_nTopWidth = wp.cy;
m_TopHeader->SetDefaultItemSize(50);
m_TopHeader->InsertItem(0,"*");
m_TopHeader->ShowWindow(SWSHOW);
}
if(1)
{
m_leftHeader = new(CHeaderCtrl,1);
m_LeftHeader->Create(0,0,wp.cx,wp.cy,0,9999,"",this);
m_LeftHeader->SetDefaultItemSize(wp.cy);
m_LeftHeader->InsertItem(0,"*");

}
if(m_hWnd)
{
if(nID)
SetWindowLongA(m_hwnd, -12, nID);
InitializeControl(this,CTCUSTOM);
}

SetFont(m_strDefaultFont,m_nDefaultFontSize,m_nDefaultFontWeight);
m_topHeader->SetFont(m_strHeaderFont,m_nHeaderFontSize,m_nHeaderFontWeight);
m_hHeaderFont = SendMessage(m_topHeader->GetHandle(),WM_GETFONT,0,0);
return nReturn;
}

CGridWnd::OnSize(int nType,int cx,int cy),int
{
RECT rc = GetClientRect(),rchead;
HDLAYOUT hdl;
WINDOWPOS wp;
if(m_topHeader)
{
rchead = m_topHeader->GetWindowRect();
hdl.prc = &rc;
hdl.pwpos = &wp;
SendMessage(m_topHeader->GetHandle(),HDM_LAYOUT,0,&hdl);
m_TopHeader->SetSize(wp.x,wp.y,wp.cx,rchead.bottom-rchead.top);
}

}

CGridWnd::OnClose(),int
{
Destroy();
return 0;
}


CGridWnd::OnLButtonDblClk(int x,int y,int flags),int
{
return 0;
}

CGridWnd::OnLButtonDown(int x,int y, int flags),int
{
int item;
int where = HitTest(x,y,&item);
if(m_bEditShown) //is the edit control shown?
{
string newtext = m_cellEdit.GetText();
gridCell *temp = *m_gridArray[m_nEditItem];
temp->m_strText = newtext;
m_cellEdit.Destroy();
InvalidateRect(GetHandle(),*m_gridRects[m_nEditItem],0);
m_bEditShown = false;
}

if(where == HIT_LEFT_RESIZE)
{
m_bDragLeft = true;
m_nDragItem = item;
SetCapture(GetHandle());
m_nDragStartY = y;
m_nDragLastY = y;
RECT rc;
m_topHeader->GetItemRect(0,&rc);
SetRasterOp(RMXORPEN);
line(0,y,rc.right,y,RGB(255,255,255));
SetRasterOp(RMCOPYPEN);
}
else if(where == HIT_CELL)
{
temp = *m_gridArray[item];
if(!temp->m_bReadOnly)
{
if(temp->m_uType == CELL_TEXT)
{
RECT rcEdit = *m_gridRects[item];
rcEdit.top--;
rcEdit.bottom++;
rcEdit.left--;
//make sure the edit control text can be seen for a minimum of 5 chars.
POINT pt = GetTextSize("XXXXX");
if((rcEdit.bottom - rcEdit.Top) < (pt.y + 4))
rcEdit.bottom = rcEdit.Top + pt.y + 4;
if((rcEdit.right - rcEdit.left) < (pt.x + 4))
rcEdit.right = rcEdit.left + pt.x + 4;

m_cellEdit.Create(rcEdit.left,rcEdit.top,rcEdit.right - rcEdit.left,rcEdit.bottom - rcEdit.top,
AWS_VISIBLE | AES_WANTRETURN | AES_MULTILINE | AES_AUTOHSCROLL | AES_AUTOVSCROLL,9997,temp->m_strText,this);
m_cellEdit.SetFont(m_strDefaultFont,m_nDefaultFontSize,m_nDefaultFontWeight);
m_nEditItem = item;
m_bEditShown = true;
SetFocus(9997);
}
else if(temp->m_uType == CELL_CHECKBOX)
{
if(temp->m_strText == "1")
temp->m_strText = "0"
else
temp->m_strText = "1";
InvalidateRect(GetHandle(),*m_gridRects[item],false);
}
}
}

return 0;
}

CGridWnd::OnLButtonUp(int x,int y,int flags),int
{
if(m_bDragLeft)
{
m_bDragLeft = false;
ReleaseCapture();
if(x!=m_nDragStartY)
{
RECT rc;
m_LeftHeader->GetItemRect(m_nDragItem,&rc);
int sz = rc.right-rc.left;
sz += (y - m_nDragStartY);
if(sz < 1)
sz = 1;
if(m_nDragItem == 0)
{
rc = m_topHeader->GetWindowRect();
m_topHeader->SetSize(0,0,rc.right-rc.left,sz);
m_nTopWidth = sz;

m_leftHeader->SetItemSize(m_nDragItem,sz);
CalculateRects();
InvalidateRect(GetHandle(),NULL,1);

}
else
{
m_leftHeader->SetItemSize(m_nDragItem,sz);
CalculateRects();
InvalidateRect(GetHandle(),NULL,1);
}

}
}
return 0;
}

CGridWnd::OnControl(int nID, int nNotifyCode, unsigned int hControl),int
{
select(nID)
{
case 9998:
if(nNotifyCode == HDN_ENDTRACK || nNotifyCode == HDN_ENDTRACKW)
{
if(m_bEditShown) //is the edit control already shown?
{
string newtext = m_cellEdit.GetText();
gridCell *temp = *m_gridArray[m_nEditItem];
temp->m_strText = newtext;
m_cellEdit.Destroy();
InvalidateRect(GetHandle(),*m_gridRects[m_nEditItem],0);
m_bEditShown = false;
}

PostMessage(GetHandle(),WM_COMMAND,9998 | ((HDN_TRACKDONE << 16) & 0xFFFF0000),hControl);
}
if(nNotifyCode == HDN_TRACKDONE)
{
CalculateRects();
InvalidateRect(GetHandle(),NULL,1);

}
}
}

//SetGridSize is destructive. It removes and reallocates the entire grid
CGridWnd::SetGridSize(uint x,uint y),int
{
int count = m_nCountX * m_nCountY;
//sanity checks
if(m_gridArray)
{
for(int z = 0;z<count;z++)
{
gridCell *temp = *m_gridArray[z];
delete temp;
}
delete m_gridArray;
}
if(m_gridRects)
delete m_gridRects;
//Allocate the grid
m_nCountX = x;
m_nCountY = y;
count = x * y;
m_gridRects = new(RECT,count);
m_gridArray = new(INT,count);
for(z = 0;z < count;z++)
{
*m_gridArray[z] = new(gridCell,1);
temp = *m_gridArray[z];
}
//set up the headers
m_topHeader->DeleteAllItems();
m_leftHeader->DeleteAllItems();
//the *
m_topHeader->InsertItem(0,"*");
m_leftHeader->InsertItem(0,"*");
for(z = 1;z < m_nCountX+1;z++)
{
m_topHeader->InsertItem(z,"");
}
for(z = 1;z < m_nCountY+1;z++)
{
m_leftHeader->InsertItem(z,"");
}
CalculateRects();
InvalidateRect(GetHandle(),NULL,1);

return true;
}

CGridWnd::AddRow(),int
{
}

CGridWnd::CalculateRects()
{
RECT rcTop;
RECT rcLeft;
RECT rcCell;
if(m_nCountX && m_nCountY)
{
if(m_topHeader && m_leftHeader)
{
int top = m_nTopWidth;
m_topHeader->GetItemRect(0,&rcTop);
int width = rcTop.right - rcTop.left;
for(int y = 1;y <= m_nCountY;y++)
{
//calculate the left header rect for this position
m_leftHeader->GetItemRect(y,&rcLeft);
height = rcLeft.right - rcLeft.left;
rcLeft.left = 0;
rcLeft.top = top;
top += height;
rcLeft.right = width;
rcLeft.bottom = rcLeft.top + height;

for(int x = 1;x <= m_nCountX;x++)
{
m_topHeader->GetItemRect(x,&rcTop);
//the cell rect is
//top.left,left.top,top.right,left.bottom
*m_gridRects[(x-1)+((y-1)*m_nCountX)].left = rcTop.left+1;
*m_gridRects[(x-1)+((y-1)*m_nCountX)].top =  rcLeft.top+1;
*m_gridRects[(x-1)+((y-1)*m_nCountX)].right = rcTop.right-1;
*m_gridRects[(x-1)+((y-1)*m_nCountX)].bottom = rcLeft.bottom-1;
}
}
}
}
}

CGridWnd::SetRowHeight(int iRow,int Height)
{
if(iRow > -1 && iRow <= m_nCountY)
{
m_leftHeader->SetItemSize(iRow,Height);
CalculateRects();
InvalidateRect(GetHandle(),NULL,1);
}
}
CGridWnd::SetColumnWidth(int iColumn,int Width)
{
if(iColumn > -1 && iColumn <= m_nCountX)
{
m_topHeader->SetItemSize(iColumn,Width);
CalculateRects();
InvalidateRect(GetHandle(),NULL,1);

}
}


//cell positions are ones based
CGridWnd::SetCellText(uint x,uint y,string text,opt uint format)
{
if((x > 0) && (x <= m_nCountX))
{
if((y > 0) && (y <= m_nCountY))
{
x--;
y--;
gridCell *temp = *m_gridArray[x+(y * m_nCountX)];
temp->m_strText = text;
temp->m_uStyle = format;
InvalidateRect(GetHandle(),*m_gridRects[x+(y * m_nCountX)],0);
}
}
}

CGridWnd::SetCellColor(uint x,uint y,uint fg,uint bg)
{
if((x > 0) && (x <= m_nCountX))
{
if((y > 0) && (y <= m_nCountY))
{
x--;
y--;
gridCell *temp = *m_gridArray[x+(y * m_nCountX)];
temp->m_cForeColor = fg;
temp->m_cBackColor = bg;
InvalidateRect(GetHandle(),*m_gridRects[x+(y * m_nCountX)],0);
}
}

}

CGridWnd::SetCellType(uint x,uint y,uint type)
{
if((x > 0) && (x <= m_nCountX))
{
if((y > 0) && (y <= m_nCountY))
{
x--;
y--;
gridCell *temp = *m_gridArray[x+(y * m_nCountX)];
temp->m_uType = type;
InvalidateRect(GetHandle(),*m_gridRects[x+(y * m_nCountX)],0);
}
}

}


//header positions are ones based
CGridWnd::SetHeaderText(int header,int iItem,string text)
{
if(header == 0)
{
if((iItem > 0) && (iItem <= m_nCountX))
{
if(m_TopHeader)
m_TopHeader->SetItemText(iItem,text);
}
}
else if(header == 1)
{
if((iItem > 0) && (iItem <= m_nCountY))
{
if(m_leftHeader)
m_leftHeader->SetItemText(iItem,text);
}
}
}

CGridWnd::ShowGridLines(int bShow)
{
m_bShowGridLines = bShow;
InvalidateRect(GetHandle(),NULL,1);
}

CGridWnd::OnPaint(),int
{
//draw the left header
int top = m_nTopWidth;
int width,height;
DrawMode(TRANSPARENT);
UINT hdc = GetHDC();
int taOld = SetTextAlign(hdc,0);
if(m_leftHeader && m_topHeader)
{
RECT rc;
m_topHeader->GetItemRect(0,&rc);
int leftCount = m_leftHeader->GetItemCount();
int topCount = m_topHeader->GetItemCount();
width = rc.right - rc.left;
uint oldFont = SelectObject(hdc,m_hHeaderFont);
for(int x=1;x < leftCount;x++)
{
m_LeftHeader->GetItemRect(x,&rc);
height = rc.right - rc.left;
rc.left = 0;
rc.top = top;
top += height;
rc.right = width;
rc.bottom = rc.top + height;
DrawFrameControl(hdc,&rc,DFC_BUTTON,DFCS_BUTTONPUSH);
rc.left += 4;
rc.top += 2;
DrawText(hdc,m_leftHeader->GetItemText(x),len(m_leftHeader->GetItemText(x)),&rc,DT_VCENTER);
}
if(oldFont)
SelectObject(hdc,oldFont);
//draw the gridlines
if(m_bShowGridlines)
{
height = top;
m_TopHeader->GetItemRect(m_TopHeader->GetItemCount()-1,&rc);
int length = rc.right;
for(x = 1;x< topCount;x++)
{
m_topHeader->GetItemRect(x,&rc);
Line(rc.right-1,rc.bottom,rc.right-1,height,m_fg);
}
top = m_nTopWidth;
for(x = 1;x< leftCount;x++)
{
m_leftHeader->GetItemRect(x,&rc);
height = rc.right - rc.left;
rc.left = 0;
rc.top = top;
top += height;
rc.right = width;
rc.bottom = rc.top + height;
line(rc.right,top-1,length,top-1,m_fg);
}
}
//draw the data
int total = m_nCountX * m_nCountY;
for(x = 0; x < total;x++)
{
gridCell *temp = *m_gridArray[x];
DrawRect(*m_gridRects[x].left-1,*m_gridRects[x].top-1,*m_gridRects[x].right - *m_gridRects[x].left + 1,*m_gridRects[x].bottom - *m_gridRects[x].top + 1,temp->m_cBackColor,temp->m_cBackColor);
FrontPen(temp->m_cForeColor);
if(temp->m_uType == CELL_TEXT)
{
DrawText(hdc,temp->m_strText,len(temp->m_strText),*m_gridRects[x],temp->m_uStyle);
}
else if(temp->m_uType == CELL_CHECKBOX)
{
}
if(m_bEditShown && m_nEditItem == x)
{
//tell the edit control to redraw since a right click menu might invalidate it.
InvalidateRect(m_CellEdit.GetHandle(),NULL,1);
}
}

}
SetTextAlign(hdc,taOld);
ReleaseHDC(hdc);
return 0;
}

CGridWnd::OnRButtonUp(int x,int y,int flags),int
{
return 0;
}

CGridWnd::OnVScroll(int nCommand,int nPos,int nID),int
{
return 0;
}

CGridWnd::OnHScroll(int nCommand,int nPos,int nID),int
{
return 0;
}

CGridWnd::OnMouseMove(int x,int y,int flags),int
{
uint hCursor = NULL;
int item;
int ht = HitTest(x,y,&item);
if(m_bDragLeft)
ht = HIT_LEFT_RESIZE;
select(ht)
{
case HIT_LEFT_RESIZE:
SetCursor(CS_CUSTOM,m_hNSCursor);
case HIT_CELL:
SetCursor(CS_CUSTOM,m_hIBeamCursor);
default:
SetCursor(CS_ARROW);
}
if(m_bDragLeft)
{
RECT rc;
m_topHeader->GetItemRect(0,&rc);
SetRasterOp(RMXORPEN);
line(0,m_nDragLastY,rc.right,m_nDragLastY,RGB(255,255,255));
line(0,y,rc.right,y,RGB(255,255,255));
m_nDragLastY = y;
SetRasterOp(RMCOPYPEN);

}
return 0;
}

CGridWnd::HitTest(int x,int y,opt int *item = NULL),int
{
POINT pt;
pt.x = x;
pt.y = y;
RECT rc;
int top = 0;//m_nTopWidth;
m_topHeader->GetItemRect(0,&rc);
int leftCount = m_leftHeader->GetItemCount();
width = rc.right - rc.left;

for(int xx=0;xx < leftCount;xx++)
{
m_LeftHeader->GetItemRect(xx,&rc);
height = rc.right - rc.left;
rc.left = 0;
rc.top = top;
top += height;
rc.right = width;
rc.bottom = rc.top + height;
//deflate the rect and check for body hit
rc.bottom -= 3;
if(!PtInRect(&rc,pt))
{
//check for edge
rc.bottom += 6;
if(PtInRect(&rc,pt))
{
if(item) {
*item = xx; }
return HIT_LEFT_RESIZE;
}

}
else
{
if(item) {
*item = xx; }
return HIT_LEFT_BUTTON;
}

}
//check for cell rects
for(xx = 0;xx < (m_nCountX * m_nCountY);xx++)
{
if(PtInRect(*m_gridRects[xx],pt))
{
if(item) {
*item = xx; }
return HIT_CELL;
}
}
if(item) {
*item = -1; }
return HIT_NOWHERE;

}

CGridWnd::SetDefaultFont(string typeface,int height,int weight,OPT int flags=0)
{
m_strDefaultFont = typeface;
m_nDefaultFontSize = height;
m_nDefaultFontWeight = weight;
SetFont(typeface,height,weight,flags);
InvalidateRect(GetHandle(),NULL,1);
}

CGridWnd::SetHeaderFont(string typeface,int height,int weight,OPT int flags=0)
{
m_strHeaderFont = typeface;
m_nHeaderFontSize = height;
m_nHeaderFontWeight = weight;

m_topHeader->SetFont(m_strHeaderFont,m_nHeaderFontSize,m_nHeaderFontWeight,flags);
m_hHeaderFont = SendMessage(m_topHeader->GetHandle(),WM_GETFONT,0,0);
}


sub main()
{
CGridWnd grid;
grid.Create(0,0,640,480,AWS_VISIBLE|AWS_SYSMENU|AWS_BORDER|AWS_CAPTION|AWS_SIZE,99,"Grid Test",0);
grid.SetGridSize(10,10);
//grid.ShowGridLines(false);
for(int x=1;x<11;x++)
{
grid.SetHeaderText(1,x,NumToStr(x));
grid.SetHeaderText(0,x,ToChar('A'-1+x));
}
grid.SetHeaderFont("Tahoma",10,700);

//grid.SetColor(rgb(255,0,0),rgb(0,0,255));
grid.SetCellText(1,1,"Test");
grid.SetCellText(2,1,"Test2");
grid.SetCellText(10,10,"Last Cell\nA multi line one",DT_WORD_ELLIPSIS);
grid.SetCellColor(1,1,RGB(255,0,0),RGB(255,255,255));
grid.SetCellColor(2,1,RGB(255,255,255),RGB(0,0,192));
grid.SetCellColor(10,10,0,RGB(255,207,0));
grid.SetRowHeight(10,40);
grid.SetColumnWidth(10,100);
while grid.IsValid() { wait(); }
}
Ionic Wind Support Team

Haim

Wow! Great work.   8)
Can't wait to have it as part of Aurora.

Thanks Paul for all your work!!

Haim

John S

February 07, 2007, 11:45:52 AM #12 Last Edit: February 07, 2007, 11:48:29 AM by John S
Paul,
When I compile and run you sample (compoles fine and runs fine), I get a "Program Error" when I close it.

Regarding cell dimensions:
1. How can I fix the cell heights and/or widths to prevent changing their size?

2. When I drag/resize the cell height, I overlap the cell above, hiding them never to uncover.  How can I prevent this?
    it looks like there needs to be a limit set somewhere in the CGridWnd::OnMouseMove or CGridWnd::HitTest methods.
John Siino, Advanced Engineering Services and Software

Ionic Wind Support Team

As stated it still needs more work.

I don't get a program error when closing.  Debug it and let me know where.

Locking resize on the row lables is relatively easy.  On the header it will require a bit more work by subclassing the windows header control and intercepting a few messages.  Just like the advanced list view demo for Emergence does.

Paul.
Ionic Wind Support Team