// Description   : NANO User Interface Framework $Revision: 12 $

// Copyright     : Proxima Centauri Romania SRL, ALL RIGHTS RESERVED. (http://www.ProximaCentauri.org)

// Author        : Alexander Ioan Mihail

 

#include "nui.h"

#include "GUI/NUI/resource.h"

#include <typeinfo.h>

#include <windows.h>

#include <windowsx.h>

#include <winuser.h>

#include <commctrl.h>

#include <RichEdit.h>

 

char        AppName[] = "NANO UI";

#define     MINSIZE        50 // The minimal width and height a childwindow should have

#define     SplitterBarSize 2

 

HWND OurSetParent(HWND self,HWND parent)

{

    if (!parent)

        BreakPoint();

    return SetParent(self,parent);

}

START_NAMESPACE(NANO_UI)

 

GApplication *GControl::qApp;

 

GControl::GControl ()

  :data(0)

{

  INIT(nullptr,nullptr,this);

}

 

GControl::~GControl ()

{

  GControl*parent=(GControl*)POYC[0];

  if (parent)

    parent->Removing(this);

}

void* GControl::userData (int aspect)

{

  return data;

}

void GControl::Remove ()

{

  BOND::Remove();

}

void GControl::setUserData (int aspect, void* value)

{

  data=value;

}

 

GApplication::GApplication (int argc, char** argv)

{

  LoadLibrary("riched20.dll");

  HWND        hwnd;

  WNDCLASS    wndclass;

  wndclass.style         = 0;

  wndclass.lpfnWndProc   = (WNDPROC)WndProc;

  wndclass.cbClsExtra    = 0;

  wndclass.cbWndExtra    = 0;

  wndclass.hInstance     = GetModuleHandle(NULL);

  wndclass.hIcon         = LoadIconA(wndclass.hInstance, MAKEINTRESOURCE(IDI_ICON1));

  wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);

  wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);

  wndclass.lpszMenuName  = AppName;

  wndclass.lpszClassName = AppName;

  RegisterClass(&wndclass);

  qApp=this;

}

void GApplication::Removing (GControl* ctrl)

{

}

int GApplication::exec ()

{

  MSG msg;

  while (GetMessage(&msg, NULL, 0, 0))

  {

    TranslateMessage(&msg);

    DispatchMessage(&msg);

  }

  return (int)msg.wParam;

}

long* GApplication::WndProc (void* hwnd, unsigned int message, unsigned int wParam, unsigned long* lParam)

{

    switch (message)

    {

        case WM_NOTIFY:

        {

            NMTREEVIEW *hdr=(NMTREEVIEW *)lParam;

            if (hdr->hdr.hwndFrom!=hwnd)

            {

                GWindow*child=(GWindow*)GWindow::FromHandle(hdr->hdr.hwndFrom);

                if (child)

                    child->HandleMessage(message, wParam, (unsigned long*)lParam);

            }

            break;

        }

    }

    GWindow*self=(GWindow*)GWindow::FromHandle(hwnd);

    if (message==WM_CREATE)

    {

        CREATESTRUCT*cs=(CREATESTRUCT*)lParam;

        self=(GWindow*)cs->lpCreateParams;

        self->SetWnd(hwnd);

        self->onCreate();

    }

    switch (message)

    {

        case WM_SIZE:

        {

            HWND hChild=GetWindow((HWND)hwnd,GW_CHILD);

            RECT rect;

            GetClientRect((HWND)self->hWnd, &rect);

            MoveWindow((HWND)hChild,rect.left,rect.top,rect.right,rect.bottom, TRUE);

            break;

        }

        case WM_SHOWWINDOW:

            break;

    }

    if (!self)

        return (long*)DefWindowProc((HWND)hwnd, message, wParam, (LPARAM)lParam);

    return self->HandleMessage(message, wParam, (unsigned long*)lParam);

}

 

GWindow::GWindow (void* hwnd)

  :hWnd(hwnd)

{

  SetWnd(hWnd);

}

 

GWindow::GWindow (GControl* parent, int flags, const char* classname)

  :hWnd(0)

{

  Insert(parent);

  if (flags==-1)

  {

    unsigned int style = WS_OVERLAPPEDWINDOW | SW_MAXIMIZE | /* WS_VISIBLE | */ 0;

    hWnd = CreateWindow(classname, classname, style, 0, 0, 600, 500, NULL, NULL, 0, this);

    SetWnd(hWnd);

  }

  else if (flags!=0)

  {

    unsigned int style=DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD |/* WS_VISIBLE | */ 0;

    if (flags==2)

      style|= WS_BORDER | WS_VSCROLL | WS_HSCROLL;

    hWnd = CreateWindow(classname, 0, style, 0, 0, 600, 500, (HWND)((GWindow*)parent)->hWnd, NULL, 0, this);

    SetParent((GWindow*)parent);

  }

}

GWindow::~GWindow ()

{

  while (POYC[3])

    delete (GControl*)POYC[3];

  if (!hWnd)

    return;

  ::CloseWindow((HWND)hWnd);

  SetWnd(0);

}

void GWindow::Removing (GControl* ctrl)

{

}

void GWindow::SetWnd (void* hwnd)

{

  if (hwnd)

  {

    hWnd=hwnd;

    SetWindowLongPtr((HWND)hWnd,GWLP_USERDATA,(LONG_PTR)this);

  }

  if (!hwnd)

  {

    SetWindowLongPtr((HWND)hWnd,GWLP_USERDATA,(LONG_PTR)0);

    hWnd=hwnd;

  }

}

void GWindow::SetParent (GWindow* parent)

{

  Insert(parent);

  if (!parent)

    ::OurSetParent((HWND)hWnd,NULL);

  else

    ::OurSetParent((HWND)hWnd,(HWND)parent->hWnd);

  show();

}

void GWindow::show ()

{

  ::ShowWindow((HWND)hWnd,SW_SHOW);

}

void GWindow::hide ()

{

  ::ShowWindow((HWND)hWnd,SW_HIDE);

}

GWindow* GWindow::FromHandle (void* hwnd)

{

  LONG_PTR ptr=GetWindowLongPtr((HWND)hwnd,GWLP_USERDATA);

  return (GWindow*)ptr;

}

long* GWindow::HandleMessage (unsigned int message, unsigned int wParam, unsigned long* lParam)

{

  return (long*)DefWindowProc((HWND)hWnd, message, wParam, (LPARAM)lParam);

}

void GWindow::onCreate ()

{

}

void GWindow::Notify(GWindow*Sender, int ctrlid)

{

}

 

GSplitter::GSplitter (GWindow* parent, int flags)

  :GWindow(parent,flags|(1<<0),AppName)

  ,A(0)

  ,B(0)

  ,Divider(320)

  ,Sizing(false)

  ,Horizontal(false)

{

}

long* GSplitter::HandleMessage (unsigned int iMsg, unsigned int wParam, unsigned long* lParam)

{

  RECT rect;

  RECT focusrect;

  HDC  hdc;

  int  Pos;

  int  err;

  static   HCURSOR hcNS = LoadCursor(NULL, IDC_SIZENS);

  static   HCURSOR hcEW = LoadCursor(NULL, IDC_SIZEWE);

  static   HCURSOR hcArrow = LoadCursor(NULL, IDC_ARROW);

  switch(iMsg)

  {

    case WM_SIZE :

      GetClientRect((HWND)hWnd, &rect);

      // Make sure splitterbars are visible

      if (!Horizontal)

      {

          if (Divider > rect.right - MINSIZE)

             Divider = rect.right - MINSIZE;

          else if(Divider < MINSIZE)

             Divider = MINSIZE;

          MoveWindow((HWND)A->hWnd, rect.left, rect.top, rect.left+Divider-SplitterBarSize, rect.bottom-rect.top, FALSE);

          MoveWindow((HWND)B->hWnd, rect.left+Divider+SplitterBarSize, rect.top, rect.right-(rect.left+Divider+SplitterBarSize), rect.bottom-rect.top, FALSE);

      }

      else

      {

          if (Divider > rect.bottom - MINSIZE)

             Divider = rect.bottom;

          else if (Divider < MINSIZE)

             Divider = MINSIZE;

          MoveWindow((HWND)A->hWnd, rect.left, rect.top, rect.right-rect.left, rect.top+Divider-SplitterBarSize , FALSE);

          MoveWindow((HWND)B->hWnd, rect.left, rect.top+Divider+SplitterBarSize, rect.right-rect.left, rect.bottom-(rect.top+Divider+SplitterBarSize), FALSE);

      }

      InvalidateRect((HWND)hWnd, &rect, TRUE);

      break;

    case WM_LBUTTONDOWN :

    {

      int xPos = (int)LOWORD(lParam);

      int yPos = (int)HIWORD(lParam);

      if (!Horizontal)

       Sizing = (xPos > Divider - SplitterBarSize && xPos < Divider + SplitterBarSize);

      else

       Sizing = (yPos > Divider - SplitterBarSize && yPos < Divider + SplitterBarSize);

      if (Sizing)

      {

         SetCapture((HWND)hWnd); // Track movement of the mousepointer

         SetCursor(Horizontal?hcNS:hcEW);

      }

      break;

   }

   case WM_LBUTTONUP :

      if (Sizing)

      {

         ReleaseCapture();

         hdc = GetDC((HWND)hWnd);

         GetClientRect((HWND)hWnd, &rect);

         if (Horizontal)

            SetRect(&focusrect, Divider-SplitterBarSize, rect.top, SplitterBarSize, rect.bottom-rect.top);

         else

            SetRect(&focusrect, rect.left, Divider-SplitterBarSize, rect.right-rect.left, SplitterBarSize);

         DrawFocusRect(hdc, &focusrect);

         Sizing=false;

         ReleaseDC((HWND)hWnd, hdc);

      }

      // Post a size message so the childwindows get their new size

      PostMessage((HWND)hWnd, WM_SIZE, 0, 0);

      break;

    case WM_MOUSEMOVE :

    {

      int xPos = (int)LOWORD(lParam);

      int yPos = (int)HIWORD(lParam);

      if (wParam == MK_LBUTTON)   // Splitter moving

      {

         if (Sizing)

         {

            hdc = GetDC((HWND)hWnd);

            GetClientRect((HWND)hWnd, &rect);

            if (!Horizontal)

            {

               SetRect(&focusrect, Divider-SplitterBarSize, rect.top, Divider, rect.bottom);

               Divider = xPos;

            }

            else

            {

               SetRect(&focusrect, rect.left, Divider-SplitterBarSize, rect.right, Divider);

               Divider = yPos;

            }

            DrawFocusRect(hdc, &focusrect);

            if (!Horizontal)

               SetRect(&focusrect, Divider-SplitterBarSize, rect.top, Divider, rect.bottom);

            else

               SetRect(&focusrect, rect.left, Divider-SplitterBarSize, rect.right, SplitterBarSize);

            DrawFocusRect(hdc, &focusrect);

            ReleaseDC((HWND)hWnd, hdc);

         }

         break;

      }

      bool could_drag;

      if (!Horizontal)

          could_drag = (xPos > Divider - SplitterBarSize && xPos < Divider + SplitterBarSize);

      else

          could_drag = (yPos > Divider - SplitterBarSize && yPos < Divider + SplitterBarSize);

      if (could_drag)

          if (!Horizontal)

          {

            if (GetCursor()!=hcEW)

              SetCursor(hcEW);

          }

          else

          {

            if (GetCursor()!=hcNS)

              SetCursor(hcNS);

          }

      else

          if (GetCursor()!=hcArrow)

            SetCursor(hcArrow);

      break;

    }

    case WM_CLOSE :

      DestroyWindow((HWND)hWnd);

      break;

    case WM_DESTROY :

      PostQuitMessage(0);

      break;

    case WM_PAINT:

        GetClientRect((HWND)A->hWnd, &rect);

        InvalidateRect((HWND)A->hWnd, &rect, TRUE);

        GetClientRect((HWND)B->hWnd, &rect);

        InvalidateRect((HWND)B->hWnd, &rect, TRUE);

        break;

  }

  return (long*)DefWindowProc((HWND)hWnd, iMsg, wParam, (LPARAM)lParam);

}

void GSplitter::SetWnds (GWindow* a, GWindow* b)

{

  a->Insert(this);

  b->Insert(this);

  A=a;

  B=b;

  PostMessage((HWND)hWnd, WM_SIZE, 0, 0);

  PostMessage((HWND)A->hWnd, WM_SIZE, 0, 0);

  PostMessage((HWND)B->hWnd, WM_SIZE, 0, 0);

}

 

GTreeItem::GTreeItem (GTreeItem* parent, enum GTreeItem::EIndicators inds)

  :host_item(0)

  ,tv(parent->tv)

  ,Count(0)

{

  parent->Count++;

  TV_INSERTSTRUCT tvins;

  tvins.hParent=(HTREEITEM)parent->host_item;              

  tvins.hInsertAfter=TVI_LAST;

  tvins.item.mask=TVIF_TEXT|TVIF_IMAGE|TVIF_CHILDREN|TVIF_PARAM;

  tvins.item.pszText=0;

  tvins.item.iImage=0;

  tvins.item.iSelectedImage=1;

  tvins.item.cChildren=1;//I_CHILDRENCALLBACK;

  tvins.item.lParam = (LPARAM)this;

  host_item=(HTREEITEM)SendMessage((HWND)tv->hWnd,TVM_INSERTITEM,0,(LPARAM)&tvins);

}

GTreeItem::GTreeItem (GTreeView* parent, enum GTreeItem::EIndicators inds)

  :host_item(0)

  ,tv(parent)

  ,Count(0)

{

  if (!parent)

    return;

  tv->Root->Count++;

  TV_INSERTSTRUCT tvins;

  tvins.hParent=NULL;              

  tvins.hInsertAfter=TVI_ROOT;

  tvins.item.mask=TVIF_TEXT|TVIF_IMAGE|TVIF_CHILDREN|TVIF_PARAM;

  tvins.item.pszText=0;

  tvins.item.iImage=0;

  tvins.item.iSelectedImage=1;

  tvins.item.cChildren=1;//I_CHILDRENCALLBACK;

  tvins.item.lParam = (LPARAM)this;

  host_item=(HTREEITEM)SendMessage((HWND)tv->hWnd,TVM_INSERTITEM,0,(LPARAM)&tvins);

}

GTreeItem::~GTreeItem ()

{

  if (!host_item)

    tv->Root->Count--;

  else

  {

    GTreeItem*p=parent();

    p->Count--;

    GTreeItem*ti;

    while (ti=child(0))

      delete ti;

    SendMessage((HWND)tv->hWnd,TVM_DELETEITEM,0,(LPARAM)host_item);

  }

}

GTreeItem* GTreeItem::parent ()

{

  HTREEITEM hitem=(HTREEITEM)host_item;

  hitem=(HTREEITEM)SendMessage((HWND)tv->hWnd,TVM_GETNEXTITEM,TVGN_PARENT,(LPARAM)hitem);

  TVITEM tvi;

  tvi.mask = TVIF_PARAM;

  tvi.hItem = (HTREEITEM)hitem;

  SendMessage((HWND)tv->hWnd,TVM_GETITEM,0,(LPARAM)&tvi);

  return (GTreeItem*)tvi.lParam;

}

int GTreeItem::childCount ()

{

  return Count;

}

GTreeItem* GTreeItem::child (int id)

{

  HTREEITEM hitem=(HTREEITEM)host_item;

  char buf[100];

  TVITEM tvi;

  hitem=(HTREEITEM)SendMessage((HWND)tv->hWnd,TVM_GETNEXTITEM,TVGN_CHILD,(LPARAM)hitem);

  while (id-->0)

  {

    if (!hitem)

      return 0;

    hitem=(HTREEITEM)SendMessage((HWND)tv->hWnd,TVM_GETNEXTITEM,TVGN_NEXT,(LPARAM)hitem);

  }

  if (!hitem)

    return 0;

  tvi.mask = TVIF_PARAM;

  tvi.hItem = hitem;

  tvi.lParam = 0;

  SendMessage((HWND)tv->hWnd,TVM_GETITEM,0,(LPARAM)&tvi);

  return (GTreeItem*)tvi.lParam;

}

bool GTreeItem::isExpanded ()

{

  unsigned int mask=TVIS_EXPANDEDONCE;

  int state=SendMessage((HWND)tv->hWnd,TVM_GETITEMSTATE,(WPARAM)host_item,(LPARAM)mask);

  if (state&TVIS_EXPANDED)

    return true;

  return false;

}

void GTreeItem::SetMeta (ELEMENT* meta)

{

  int id=meta->GetId();

  TVITEM tvi;

  memset(&tvi,0,sizeof(tvi));

  tvi.hItem=(HTREEITEM)host_item;

  tvi.mask=TVIF_IMAGE;

  tvi.iImage=id-1;

  HWND hTree=(HWND)tv->hWnd;

  int rv0=SendMessage((HWND)tv->hWnd,TVM_SETITEM,0,(LPARAM)&tvi);

}

GString GTreeItem::text (int aspect)

{

  char buf[100];

  GetText(aspect,buf,sizeof(buf));

  if (buf[0]==0)

    return "";

  return (GString)-1; // Use GetText.

}

void GTreeItem::GetText (int aspect, GString s, int length)

{

  TVITEM tvi;

  tvi.mask=TVIF_TEXT;

  tvi.hItem = (HTREEITEM)host_item;

  tvi.cchTextMax = length;

  tvi.pszText = s;

  int rv0=SendMessage((HWND)tv->hWnd,TVM_GETITEM,0,(LPARAM)&tvi);

}

void GTreeItem::setText (int aspect, GString s)

{

  if (aspect==2)

  {

    if (s&&s[0])

      BreakPoint();

    else

      return;

  }

  if (aspect==1)

    return;

  TVITEM tvi;

  memset(&tvi,0,sizeof(tvi));

  tvi.hItem=(HTREEITEM)host_item;

  tvi.mask=TVIF_TEXT;

  tvi.stateMask=TVIF_TEXT;

  if (aspect==2&&s)

  {

    char buf[100];

    buf[0]=0;

    tvi.pszText=buf;

    tvi.cchTextMax = sizeof(buf);

    int rv0=SendMessage((HWND)tv->hWnd,TVM_GETITEM,0,(LPARAM)&tvi);

    sprintf(buf+strlen(buf)," (%s)",s);

    tvi.pszText=buf;

  }

  else

    tvi.pszText=s;

  int rv0=SendMessage((HWND)tv->hWnd,TVM_SETITEM,0,(LPARAM)&tvi);

}

 

GTreeView::GTreeView (GWindow* parent)

  :GWindow(0)

  ,Dragging(false)

  ,hEdit(0)

{

  unsigned int tv_style = TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_EDITLABELS | TVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP;

  hWnd=CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEW, "Browser", tv_style | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, 0, 0, 0, 0, (HWND)parent->hWnd, NULL, 0, this);

  SetWnd(hWnd);

  SetParent(parent);

  Root=new GTreeItem((GTreeView*)0,GTreeItem::UserType);

  Root->tv=this;

  onCreate();

}

long* GTreeView::HandleMessage (unsigned int message, unsigned int wParam, unsigned long* lParam)

{

  HWND hTree=(HWND)hWnd; //GetDlgItem(hWnd,IDC_TREE);

  GTreeView*tv=(GTreeView*)GWindow::FromHandle((HWND)hWnd);

  switch (message)

  {

            case WM_LBUTTONDOWN:

                  ReleaseCapture();

                  SendMessage((HWND)hWnd,WM_NCLBUTTONDOWN,HTCAPTION,0);

            break;

            case WM_NOTIFY:

            {

            // IDC_TREE:

            switch (((LPNMHDR)lParam)->code)

            {

                case TVN_ITEMEXPANDING:

                    {

                    TVITEM tvi;

                    NMTREEVIEW *hdr=(NMTREEVIEW *)lParam;

                    tvi.mask = TVIF_PARAM;

                    tvi.hItem = hdr->itemNew.hItem;

                    SendMessage((HWND)hWnd,TVM_GETITEM,0,(LPARAM)&tvi);

                    QModelIndex mi;

                    mi.ptr=(GTreeItem*)tvi.lParam;

                    tvi.mask=TVIF_STATE;

                    tvi.stateMask=TVIS_EXPANDED|TVIS_BOLD;

                    SendMessage((HWND)hWnd,TVM_GETITEM,0,(LPARAM)&tvi);

                    if (tvi.state&TVIS_EXPANDED)

                    {

                        tv->onCollapsed(mi);

                        tvi.state&=~TVIS_EXPANDED;

                        SendMessage((HWND)hWnd,TVM_SETITEM,0,(LPARAM)&tvi);

                    }

                    else

                    {

                        tvi.state|=TVIS_EXPANDED;

                        //tvi.state|=TVIS_BOLD;

                        SendMessage((HWND)hWnd,TVM_SETITEM,0,(LPARAM)&tvi);

                        tv->onExpanded(mi);

                    }

                    break;

                    }

                case NM_DBLCLK:

                    {

                    QModelIndex mi;

                    mi.ptr=tv->currentItem();

                    tv->onItemDoubleClicked(mi);

                    break;

                    }

                case NM_CLICK:

                    BreakPoint();

                    break;

                case NM_RCLICK:

                    break;

                case TVN_BEGINDRAG:

                    {

                          HIMAGELIST hImg;

                          LPNMTREEVIEW lpnmtv = (LPNMTREEVIEW) lParam;

                          hImg=TreeView_CreateDragImage(hTree, lpnmtv->itemNew.hItem);

                          ImageList_BeginDrag(hImg, 0, 0, 0);

                          ImageList_DragEnter(hTree,lpnmtv->ptDrag.x,lpnmtv->ptDrag.y);

                          ShowCursor(FALSE);

                          SetCapture((HWND)hWnd);

                          tv->Dragging = TRUE;

                    break;

                    }

                case TVN_BEGINLABELEDIT:

                            tv->hEdit=TreeView_GetEditControl(hTree);

                    break;

                case TVN_ENDLABELEDIT:

                    {

                    HTREEITEM Selected=(HTREEITEM)SendMessage((HWND)hWnd,TVM_GETNEXTITEM,TVGN_CARET,(LPARAM)0);

                          if (!Selected)

                                break;

                          char Text[256]="";

                          GetWindowText((HWND)tv->hEdit, Text, sizeof(Text));

                          TV_ITEM tvi;

                          tvi.hItem=Selected;

                          tvi.mask = TVIF_TEXT;

                          tvi.pszText=Text;

                          SendMessage((HWND)hWnd,TVM_SETITEM,0,(WPARAM)&tvi);

                    break;

                    }

              } // end switch

              break;

        }

            case WM_MOUSEMOVE:

                  if (tv->Dragging)

                  {

                        POINTS Pos = MAKEPOINTS(lParam);

                        ImageList_DragMove(Pos.x-32, Pos.y-25); // where to draw the drag from

                        ImageList_DragShowNolock(FALSE);

                        TVHITTESTINFO tvht;

                        tvht.pt.x = Pos.x-20;

                        tvht.pt.y = Pos.y-20;

                        HTREEITEM hitTarget;

                        if (hitTarget=(HTREEITEM)SendMessage((HWND)hWnd,TVM_HITTEST,NULL,(LPARAM)&tvht))

                              SendMessage(hTree,TVM_SELECTITEM,TVGN_DROPHILITE,(LPARAM)hitTarget);

                        ImageList_DragShowNolock(TRUE);

                  }

            break;

        case WM_LBUTTONUP:

            if (tv->Dragging)

            {

                ImageList_DragLeave(hTree);

                ImageList_EndDrag();

                HTREEITEM Selected=(HTREEITEM)SendMessage((HWND)hWnd,TVM_GETNEXTITEM,TVGN_DROPHILITE,0);

                SendMessage((HWND)hWnd,TVM_SELECTITEM,TVGN_CARET,(LPARAM)Selected);

                SendMessage((HWND)hWnd,TVM_SELECTITEM,TVGN_DROPHILITE,0);

                ReleaseCapture();

                ShowCursor(TRUE);

                tv->Dragging = FALSE;

            }

            break;

        case WM_COMMAND: // Buttons

            break;

        case WM_PAINT:

            BreakPoint();

            break;

  }

  return 0;

}

void GTreeView::onCreate ()

{

  HIMAGELIST hImageList=ImageList_Create(16,16,ILC_COLOR24,0,10);

  ELEMENT*th=ELEMENT::GetThread();

  CAT_CORE*cat=th->GetKernel();

  ELEMENT*meta=&cat->Types[CAT_CORE::em_META];

  ELEMENT*var=nullptr;

  int count=0;

  FOR_INSTANCES_OF(meta)

    void*buf;

    int size;

    var->GetBitmapData(buf,size);

    HBITMAP hBmp=buf?(HBITMAP)Buffer2Bmp((char*)buf):0;

    int id=var->GetId();

    while (++count<id)

      ImageList_Add(hImageList,hBmp,NULL);

    ImageList_Add(hImageList,hBmp,NULL);

    DeleteObject(hBmp);

  FOREND

  SendMessage((HWND)hWnd,TVM_SETIMAGELIST,0,(LPARAM)hImageList);

}

GTreeItem* GTreeView::invisibleRootItem ()

{

  return Root;

}

GTreeItem* GTreeView::currentItem ()

{

  TVITEM tvi;

  tvi.mask = TVIF_PARAM;

  tvi.hItem = (HTREEITEM)SendMessage((HWND)hWnd,TVM_GETNEXTITEM,TVGN_CARET,(LPARAM)0);

  SendMessage((HWND)hWnd,TVM_GETITEM,0,(LPARAM)&tvi);

  return (GTreeItem*)tvi.lParam;

}

 

GTabControl::GTabControl (GWindow* parent)

  :GWindow(0)

  ,Current(0)

{

  unsigned int tv_style =

        WS_BORDER |

        WS_CHILD |

        WS_CLIPCHILDREN |

        WS_CLIPSIBLINGS |

        WS_VISIBLE |

        //TCS_FOCUSNEVER |

        TCS_TABS |

        //TCS_SINGLELINE |

        //TCS_OWNERDRAWFIXED |

        0;

  hWnd=CreateWindowExA(WS_EX_CLIENTEDGE | TCS_EX_FLATSEPARATORS,

      WC_TABCONTROL, "Tabs", tv_style | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, 0, 0, 0, 0, (HWND)parent->hWnd, NULL, 0, this);

  SetWnd(hWnd);

  SetParent(parent);

}

void GTabControl::Removing (GControl* ctrl)

{

  GWindow*w=(GWindow*)ctrl;

  HWND hTab=(HWND)hWnd;

  int count=TabCtrl_GetItemCount(hTab);

  for (int i=0;i<count;i++)

  {

    TCITEM tie;

    memset(&tie,0,sizeof(tie));

    tie.mask = TCIF_PARAM;

    TabCtrl_GetItem(hTab,i,&tie);

    if (ctrl==(GWindow*)tie.lParam)

    {

      TabCtrl_DeleteItem(hTab,i);

      break;

    }

  }

  if (Current==w)

  {

    Current=(GTabPage*)w->POYC[2];

    if (Current)

    {

        RECT rect;

        GetClientRect((HWND)Current->hWnd, &rect);

        SetWindowPos((HWND)Current->hWnd, HWND_TOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOREPOSITION|SWP_ASYNCWINDOWPOS|SWP_SHOWWINDOW );

        Current->show();

    }

  }

}

long* GTabControl::HandleMessage (unsigned int message, unsigned int wParam, unsigned long* lParam)

{

  switch (message) // what are we doing ?

  {

       case WM_INITDIALOG:

            break;

       case WM_SIZE :

       {

            RECT rect;

            GetClientRect((HWND)hWnd, &rect);

            HWND h=GetDlgItem((HWND)hWnd,IDC_TAB);

            MoveWindow(h,rect.left,rect.top,rect.right-rect.left,rect.bottom-rect.top,true);

            break;

       }

       case WM_PAINT:

            if (Current)

            {

                RECT rect;

                GetClientRect((HWND)Current->hWnd, &rect);

                InvalidateRect((HWND)Current->hWnd, &rect, TRUE);

            }

            break;

       case WM_NOTIFY:

       {

           NMHDR*hdr=(NMHDR*)lParam;

           switch (hdr->code)

           {

                case TCN_FOCUSCHANGE:

                    BreakPoint();

                    break;

                case TCN_GETOBJECT:

                    BreakPoint();

                    break;

                case TCN_SELCHANGING:

                    BreakPoint();

                    break;

                case TCN_SELCHANGE:

                {

                    if (Current)

                        Current->hide();

                    HWND hTab=hdr->hwndFrom;

                    int page_id=TabCtrl_GetCurSel(hTab);

                    TCITEM tie;

                    memset(&tie,0,sizeof(tie));

                    tie.mask = TCIF_PARAM;

                    TabCtrl_GetItem(hTab,page_id,&tie);

                    Current=(GTabPage*)tie.lParam;

                    if (Current)

                        Current->show();

                    break;

                }

           }

           BreakPoint();

           break;

       }

  }

  return GWindow::HandleMessage(message, wParam, lParam);

}

void GTabControl::onCreate ()

{

  HWND hTab=(HWND)hWnd;

  char buf[100];

  sprintf(buf,"%s %s %s","NANO","2.0",ELEMENT::GetVersion());

  GTabPage*child=new GTabPage(this,IDD_ABOUT);

  HWND hVersion=GetDlgItem((HWND)child->hWnd,IDC_STATIC_ABOUT_VERSION);

  Edit_SetText(hVersion,buf);

  AddPage("About",child);

}

GTabPage* GTabControl::AddPage (GString name, GTabPage* child)

{

  HWND hTab=(HWND)hWnd;

  if (child)

  {

    child->SetParent(this);

    PostMessage((HWND)child->hWnd, WM_SIZE, 0, 0);

    //child->WClass=GWindow::ewPage;

    SetWindowText((HWND)child->hWnd,name);

  }

  TCITEM tie;

  memset(&tie,0,sizeof(tie));

  tie.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;

  tie.iImage = -1;

  tie.pszText = name;

  tie.lParam=(LPARAM) child;

  int id=TabCtrl_InsertItem(hTab, 0, &tie);

  Current=child;

  TabCtrl_SetCurSel(hTab,id);

  return child;

}

 

GTimer::GTimer (GWindow* win)

  :Win(win)

{

}

void GTimer::start (int period)

{

  id=(void*)SetTimer((HWND)Win->hWnd,(UINT_PTR)this,period,(TIMERPROC)DoTimeout);

}

void GTimer::DoTimeout (void* hwnd, int msg, void* id, unsigned int time)

{

  GTimer*self=(GTimer*)id;

  self->timeout();

}

 

GTabPage::GTabPage (GTabControl* parent, int resid)

  :GWindow(parent,resid==0?-1:0,AppName)

{

  if (!hWnd)

  {

    HWND h=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(resid),(HWND)parent->hWnd,(DLGPROC)DlgProc);

    SetWnd(h);

    SetParent(parent);

  }

}

GTabPage::~GTabPage ()

{

  EndDialog((HWND)hWnd,0);

  SetWnd(0);

}

long* GTabPage::DlgProc (void* hwnd, unsigned int message, unsigned int wParam, unsigned long* lParam)

{

  GTabPage*self=(GTabPage*)GWindow::FromHandle(hwnd);

  if (message==WM_INITDIALOG)

  {

    HWND hparent=GetParent((HWND)hwnd);

    if (!hparent)

      BreakPoint();

    else

    {

      RECT rect;

      GetClientRect(hparent, &rect);

      MoveWindow((HWND)hwnd,rect.left,rect.top+24,rect.right-4,rect.bottom, FALSE);

    }

    return 0;

  }

  if (!self)

      return 0;

  return self->DlgMessage(message,wParam,lParam);

}

long* GTabPage::DlgMessage (unsigned int message, unsigned int wParam, unsigned long* lParam)

{

  switch(message)

  {

    case WM_SIZE:

    {

      HWND hChild=GetWindow((HWND)((GWindow*)POYC[0])->hWnd,GW_CHILD);

      RECT rect;

      GetClientRect((HWND)hWnd, &rect);

      MoveWindow((HWND)hWnd,rect.left,rect.top+24,rect.right-4,rect.bottom, FALSE);

      break;

    }

    case WM_NOTIFY:

    {

      BreakPoint();

      break;

    }

    case WM_COMMAND:

    {

      if (wParam==IDCANCEL)

      {

        delete this;

        break;

      }

      GWindow*root=this;

      while (root->POYC[0])

        root=(GWindow*)root->POYC[0];

      root->Notify(this,wParam);

      break;

    }

  }

  return 0;

}

 

GEdit::GEdit (GWindow* parent)

  :GWindow(parent,2,RICHEDIT_CLASS)

{

  Access(+1,0,"Log started\r\n",0,0);

}

int GEdit::Access (int direction, int offset, char* buf, int len, int flags)

{

  SETTEXTEX sext;

  sext.flags=ST_DEFAULT;

  sext.codepage=CP_ACP;

  SendMessage((HWND)hWnd,EM_REPLACESEL,(WPARAM)&sext,(LPARAM)buf);

  //SendMessage((HWND)hWnd, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);

  return 0;

}

 

END_NAMESPACE(NANO_UI)