IonicWind Software

Aurora Compiler => Software Projects => Topic started by: Ionic Wind Support Team on October 16, 2006, 02:14:28 AM

Title: Grid control in development
Post by: Ionic Wind Support Team on October 16, 2006, 02:14:28 AM
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(); }
}


Title: Re: Grid control in development
Post by: Kale on October 16, 2006, 03:48:08 AM
This will maybe help:

http://www.ionicwind.com/forums/index.php?topic=878.0
Title: Re: Grid control in development
Post by: J B Wood (Zumwalt) on October 16, 2006, 06:54:16 AM
What is this based on?
Title: Re: Grid control in development
Post by: Ionic Wind Support Team on October 16, 2006, 09:38:49 AM
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.
Title: Re: Grid control in development
Post by: J B Wood (Zumwalt) on October 16, 2006, 10:11:07 AM
I am impressed.
Title: Re: Grid control in development
Post by: Bruce Peaslee on October 16, 2006, 11:28:54 AM
Neat. If you decide to give it away, does that mean you would add the control to Aurora or just distribute the code?
Title: Re: Grid control in development
Post by: Steven Picard on October 16, 2006, 11:45:06 AM
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
Title: Re: Grid control in development
Post by: Ionic Wind Support Team on October 16, 2006, 02:22:13 PM
Probably a week to finish the base code. 

Title: Re: Grid control in development
Post by: Ionic Wind Support Team on October 23, 2006, 02:09:11 AM
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.
Title: Re: Grid control in development
Post by: Haim on October 23, 2006, 03:22:21 AM
Great news!

Haim
Title: Re: Grid control in development
Post by: Ionic Wind Support Team on January 28, 2007, 09:47:10 PM
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(); }
}
Title: Re: Grid control in development
Post by: Haim on January 28, 2007, 10:18:46 PM
Wow! Great work.   8)
Can't wait to have it as part of Aurora.

Thanks Paul for all your work!!

Haim
Title: Re: Grid control in development
Post by: John S on February 07, 2007, 11:45:52 AM
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.
Title: Re: Grid control in development
Post by: Ionic Wind Support Team on February 07, 2007, 11:55:05 AM
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.