SOL9 2.0 Class: View

 SOL9 C++ Class Library  SOL9 Samples  SOL9 Tutorial  SOL9 FAQ  SOL9 ClassTree  SOL9 ClassList 

Source code

/******************************************************************************
 *
 * Copyright (c) 1999-2009 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 *  
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *  View.h
 *
 *****************************************************************************/

// SOL9

// 1999.08.14
// 2000.02.18
// 2001.03.11 to-arai: Added a create method.
// 2012/07/22 Updated getCallbackName method
// 2015/08/22 Added activate method.
// 2016/08/10 Added the virtual specifier to postRewieRequest, and postRenderRequest methods.

#pragma once

#include <sol/Wchardef.h>
#include <sol\Window.h>
#include <sol\Application.h>

#include <sol\Args.h>
#include <sol\CallbackList.h>
#include <sol\HandlerList.h>
#include <sol\Dimension.h>
#include <sol\LinkedList.h>
#include <sol\Layoutable.h>
#include <sol\stdio.h>
#include <sol\Font.h>
#include <sol\InvalidWindowException.h>


namespace SOL {

class Font;
class Layoutable;

class View :public Window, public Layoutable {
private:
  View*      parent;
  Font*      font;  
  CallbackList  callbackList;
  HandlerList    handlerList;
  Boolean      editable;
  Boolean      destructable;
  Dimension    preferredSize;
  
  public:
  static const long  DEFAULT_WIN_CLASS_STYLE = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;


protected:
   virtual long destroy(Event& event)
  {
    ::PostQuitMessage(0);
    return 0L;
  }

protected:
   virtual LRESULT defaultProc(Event& event)
  {
    return ::DefWindowProc(getWindow(), event.getMessage(),
           event.getWParam(),
           event.getLParam());
  }

protected:
  View(View* parview)
    :parent(parview),
    font(NULL),
    editable(False),
    destructable(True),
    preferredSize(100, 100)
  {
    //
  }

public:
  View()
    :parent(NULL),
    font(NULL),
    editable(False),
    destructable(True),
    preferredSize(100, 100)
  {
  }

public:
  View(View* parview, const TCHAR* name, Args& args)
    :parent(parview),
    font(NULL),
    editable(False),
    destructable(True),
    preferredSize(100, 100)
  {
    Boolean rc = create(parview, name, args);
    if (rc == False) {
      throw IException("Failed to create a window");
    }
  }


public:
  ~View()
  {
    HWND hwnd = getWindow();
    if(isWindow() && destructable) {
      destroyWindow();
    }
    Application::remove(hwnd);
  }

public:
  virtual void  addCallback(const TCHAR* name, Object* object,
           Callback proc, void* data)
  {
    if(parent) {
      parent -> addCallback(name, (const Key)getWindow(), object, 
              proc, data);
    }
  }


public:
  void  addCallback(const TCHAR* name, const Key key, Object* object,
           Callback proc, void* data)
  {
    callbackList.add(name, key, object, proc, data);
  }


public:
  void  addEventHandler(UINT message, Object* object,
               Handler proc, void* data)
  {
    handlerList.add(message, object, proc, data);
  }

public:
  void  callCallback(const TCHAR* name, const Key key, 
      void* value, Event& event)
  {
    callbackList.call(name, key, value, event);
  }
  
public:
  virtual Boolean create(View* parview, const TCHAR* name, Args& args)
  {
    Boolean rc = False;

    parent = parview;
    font   = NULL;
    editable = False;
    destructable = True;

    // If a window were created, return False.
    if (getWindow()) {
      return rc;
    }

    if (args.get(XmNdialogUnit)) {
      args.toPixelUnit();
    }

    const TCHAR* className = nullptr;
    className = (const TCHAR*)args.get(XmNclassName);//, &val);
    //MessageBox(NULL, className, _T("ClassName"), MB_OK);
    if (className == nullptr) {
      className = _T("View");
      args.set(XmNclassName, (LONG_PTR)className);
    }

    if (args.get(XmNpredefined) == False){
      registerClass(args);
    }

    HFONT hfont = NULL;

    HWND hparent = NULL;
    Font* pfont =NULL;

    if (parent) {
      hparent = parent->getWindow();

      //If parent has a Font, then we use it.
      pfont    = parent->getFont();
      if (pfont) {
        hfont = pfont->getFont();
      }
    }
    Application& applet = Application::getApplet(NULL);
    HINSTANCE hInstance = applet.getInstance();
    
    HWND hwnd= ::CreateWindowEx(
          (DWORD)args.get(XmNexStyle),  //2017/09/10
          className, name,
          (DWORD)args.get(XmNstyle),
          (int) args.get(XmNx),
          (int) args.get(XmNy),
          (int) args.get(XmNwidth),
          (int) args.get(XmNheight),
          hparent, NULL,
          hInstance,  //Application::getInstance(),
          (LPSTR)args.get(XmNparam));
  
    if(hwnd) {
      setWindow(hwnd);

      Application::add(hwnd, this);
      setViewId((int)args.get(XmNid));
    
      //<added date="2008/06/27">
      TCHAR* useDefaultFont = (TCHAR*)args.get(XmNuseDefaultFont);

      if (hfont && useDefaultFont) {
        SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(True,0));
        if (pfont) {
          setFont(pfont);
        }
      }
      //</added>
      if(parent == NULL) {
        addEventHandler(WM_DESTROY, this,
               (Handler)&View::destroy, NULL);
      }
      rc = True;
    }
    else {
      //2012/07/20
      throw TException(_T("Failed to CreateWindow className:'%s'"), className);
    }
    return rc;
  }

  BOOL registerClass(Args& args)
  {
    BOOL rc = FALSE;
    //Application& applet = getInstance();
    Application& applet = Application::getApplet(NULL);
    HINSTANCE hInstance = applet.getInstance();

    WNDCLASS wc;
    const TCHAR* className = (const TCHAR*)args.get(XmNclassName);

   // MessageBox(NULL, (_TCHAR*)className, _T("Register DEBUG"), MB_OK);
    if (::GetClassInfo(hInstance, (_TCHAR*)className, &wc)) {
      return TRUE;
    }
    HINSTANCE  prevInstance = applet.getPrevInstance(); 

    if (!prevInstance) {
    
      memset(&wc, 0, sizeof(WNDCLASS));
      wc.hCursor   = LoadCursor(NULL, IDC_ARROW);
      wc.hIcon   = LoadIcon(NULL, IDI_APPLICATION);
      wc.lpszClassName = (_TCHAR*)className;
      wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
      wc.hInstance     = hInstance;
      wc.style         = DEFAULT_WIN_CLASS_STYLE;
      //CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
      wc.lpfnWndProc   = View::procedure;

      LONG_PTR val=0;
      if (args.get(XmNclassStyle, &val)) {
        wc.style      = (unsigned int)val;
      }
      if (args.get(XmNclsExtra, &val)) {
        wc.cbClsExtra = (unsigned int)val;
      }
      if (args.get(XmNwndExtra, &val)) {
        wc.cbWndExtra  = (unsigned int)val;
      }
      if (args.get(XmNwndProc, &val)) {
        wc.lpfnWndProc = (WNDPROC)val;
      }
      if (args.get(XmNbackground, &val)) {
        wc.hbrBackground = (HBRUSH)val;
      }
      if (args.get(XmNicon, &val)) {
        wc.hIcon      = (HICON)val;
      }
      if (args.get(XmNcursor, &val)) {
        wc.hCursor    = (HCURSOR)val;
      }
      //return 
      rc = ::RegisterClass(&wc);
      if (rc) {
        return rc;
      } else {
        throw TException(_T("Failed to RegisterClass"));
      }
    }
    return rc;
  }

  // 2001.03.11
public:
  virtual Boolean create(View* parview)
  {
    parent  = parview;
    font  = NULL;
    editable = False;
    destructable = True;
    Dimension d(100,100);
    preferredSize.set(d);
    return True;
  }

public:
  virtual void disable()
  {
    show(SW_HIDE);
    enableWindow(False);
    show(SW_NORMAL);
  }

public:
  virtual LRESULT  dispatch(Event& event)
  {
    LONG_PTR value = NULL;
    event.handled(false);
    if(handlerList.call(event, &value)) {
      event.handled(true);
      return value;
    }
    return defaultProc(event);
  }

public:
  virtual void  enable()
  {
    show(SW_HIDE);
    enableWindow(True);
    show(SW_NORMAL);
  }

public:
  LONG_PTR get(const TCHAR* name)
  {
    LONG_PTR val;
    Args args;
    args.set(name, (LONG_PTR)&val);
    getValues(args);
    return val;
  }


public:
  void get(const TCHAR* name, LONG_PTR* val)
  {
    Args args;
    args.set(name, (LONG_PTR)val);
    getValues(args);
  }
  
public:
  virtual Arg*  getCallbackTable(int* num)
  {
    *num = 0;
    return NULL;
  }

public:
  virtual const TCHAR* getCallbackName(Event& event)
  {
    int  num = 0;
    Arg* table = NULL;

    table = getCallbackTable(&num);

    LONG_PTR val = (LONG_PTR)event.getNotification();
    //2012/07/22
    const TCHAR* name = NULL;
    //const TCHAR* name = XmNactivateCallback;

    for(int i = 0; i<num; i++) {
      if(table[i].value == val) {
        name = table[i].name;
        break;          
      } 
    }
    return name;
  }

public:
  void  getGeometry(int& x, int& y, int& width, int& height)
  {
    RECT r;
    getWindowRect(&r);
    x   = r.left;
    y   = r.top;
    width  = r.right  - r.left;
    height = r.bottom - r.top;

    if(parent) {
      POINT p;
      p.x = x;
      p.y = y;
      parent -> toClient(&p);
      x = p.x;
      y = p.y;
    }
  }

public:
  void  getNormalPlacement(RECT* r)
  {
    WINDOWPLACEMENT pl;
    pl.length = sizeof(WINDOWPLACEMENT);
    pl.showCmd = SW_SHOWNORMAL;
    getPlacement(&pl);
    *r = pl.rcNormalPosition;
  }

public:
  View*  getParent() { 
    return parent; 
  }
  
public:
  void  getSize(int& width, int& height)
  {
    RECT r;
    getWindowRect(&r);
    width  = r.right  - r.left;
    height = r.bottom - r.top;
  }

public:
  void  getLocation(int& x, int& y)
  {
    int width, height;
    getGeometry(x, y, width, height);
  }

public:
  int    getViewId() { 
    return getId(); 
  }
  
public:
  virtual void  layout(int x, int y, int w, int h)
  {
    reshape(x, y, w, h);
  }

public:
  Boolean  isEditable() { 
    return editable; 
  }
  
public:
  void  map() { 
    show(SW_NORMAL); 
  }

public:
  virtual void  getValues(Args& args)
  {
    int x, y, w, h;
    getGeometry(x, y, w, h);

    Arg ar[4];
    XtSetArg(ar[0], XmNx,     x);
    XtSetArg(ar[1], XmNy,     y);
    XtSetArg(ar[2], XmNwidth, w);
    XtSetArg(ar[3], XmNheight,h);

    HINSTANCE ins = getInstanceHandle();

    int num   = args.getCount();
    Arg* arg  = args.getArgList();

    LONG style   = (LONG)(getWindowLongPtr(GWL_STYLE));
    LONG exStyle = (LONG)(getWindowLongPtr(GWL_EXSTYLE));

    for(int j = 0; j<num; j++) {
      const TCHAR*   name  = arg[j].name;
      LONG_PTR* val  = (LONG_PTR*)arg[j].value;
      if(name == XmNstyle) {
        *val = style;
        continue;
      }
      if(name == XmNexStyle) {
        *val = exStyle;
        continue;
      }
      if(name == XmNid) {
        *val = getViewId();
        continue;
      }
      if(name == XmNinstance) {
        *val = (LONG_PTR)ins;
        continue;
      }
      if(name == XmNgroup) {
        *val = False;
        if(style & WS_GROUP) 
          *val = True;
        continue;
      }
      if(name == XmNacceptFiles) {
        *val = False;
        if(exStyle & WS_EX_ACCEPTFILES)
          *val = True;
        continue;
      }
  
      if(name == XmNlabelString) {
        int len = getTextLength();
        TCHAR* buff = new TCHAR[len+1];
        getText(buff, len+1);
        *val = (LONG_PTR)buff;
      }
    
      for(int i = 0; i<4; i++) {
        if(name == ar[i].name) {
           *val = (LONG_PTR)ar[i].value;
        }
      }
    }
  }


public:
  static LRESULT CALLBACK procedure(HWND hwnd, UINT message, 
      WPARAM wParam, LPARAM lParam)
  {
    Event event(message, wParam, lParam);

    View* view = Application::lookup(hwnd);

    if (view && view->isWindow()) {
      return view -> dispatch(event);
    }
    return ::DefWindowProc(hwnd, message, wParam, lParam);
  }

public:
  void  removeEventHandler()
  {
    handlerList.clear();
  }

public:
  void  set(const TCHAR* name, LONG_PTR val)
  {
    Args args;
    args.set(name, val);
    setValues(args);
  }


public:
  void  setDestructable(Boolean val) { 
    destructable = val;
  }

public:
  void  setEditable(Boolean val) { 
    editable = val; 
  }
  
public:
  void  setLocation(int x, int y)
  {
    int xx, yy, width, height;

    getGeometry(xx, yy, width, height);
    reshape(x, y, width, height);
    update(NULL);
  }

public:
  void  setSize(int w, int h)
  {
    int xx, yy, width, height;

    getGeometry(xx, yy, width, height);
    reshape(xx, yy, w, h);
    update(NULL);
  }

  
public:
  void  setParent(View* parent1) { 
    parent = parent1; 
  }

public:
  void  setViewId(int id)
  {
    setId(id);
    LONG style = (LONG)getWindowLongPtr(GWL_STYLE);
    if(style & WS_CHILD) {
      setWindowLongPtr(GWLP_ID, (LONG_PTR)id);
    }
  }


public:
  void  setVisible(Boolean flag) 
  {
    if (flag) 
      map();
    else 
      unmap();
  }

public:
  virtual void  setValues(Args& args)
  {
    int x, y, w, h;

    getGeometry(x, y, w, h); 
    Arg ar[4];
    XtSetArg(ar[0], XmNx,     x);
    XtSetArg(ar[1], XmNy,     y);
    XtSetArg(ar[2], XmNwidth, w);
    XtSetArg(ar[3], XmNheight,h);

    Boolean mustmove = False;
    int num  = args.getCount();
    Arg* arg = args.getArgList();
    int i, j;
    for(j = 0; j<num; j++) {
      for(i = 0; i<4; i++) {
        if(ar[i].name == arg[j].name) {
           ar[i].value = arg[j].value;
          mustmove = True;
        }
      }
    }
    Boolean config = (Boolean)args.get(XmNnoConfiguration);
    if(!config) {
      if(mustmove && (ar[2].value != (LONG_PTR)CW_USEDEFAULT) ||
                       (ar[3].value != (LONG_PTR)CW_USEDEFAULT)) {
        reshape((int)ar[0].value, (int)ar[1].value,
                   (int)ar[2].value, (int)ar[3].value);
      }
    }
    LONG_PTR val = 0;
    LONG_PTR style   = (LONG_PTR)getWindowLongPtr(GWL_STYLE);
    LONG_PTR exStyle = (LONG_PTR)getWindowLongPtr(GWL_EXSTYLE);

    if(args.get(XmNgroup, &val)) {
      if(val) {
        style |= WS_GROUP;
      }
      else {
        if(style & WS_GROUP) 
          style ^= WS_GROUP;
      }
      setWindowLongPtr(GWL_STYLE, (LONG_PTR)style);
    }

    if(args.get(XmNacceptFiles, &val)) {
      if(val) {
        exStyle |= WS_EX_ACCEPTFILES;
      }
      else {
        if(exStyle & WS_EX_ACCEPTFILES)
          exStyle ^= WS_EX_ACCEPTFILES;
      }
      setWindowLongPtr(GWL_EXSTYLE, (LONG_PTR)exStyle);
    }
    if(args.get(XmNlabelString, &val)) {
      setText((TCHAR*)val);
    }

    if(args.get(XmNid, &val)) {
      setViewId((int)val);
    }
  }


public:
  void  getStyle(Args& args, Arg* arg, int num)
  {
    LONG_PTR style = (LONG_PTR)getWindowLongPtr(GWL_STYLE);

    for(int i = 0; i<num; i++) {
      LONG_PTR* val = (LONG_PTR*)args.get(arg[i].name);
      if(val) {
        *val = False;
        if(style & (DWORD)arg[i].value)
          *val = True;
      }
    }
  }

public:
  void  unmap() { 
    show(SW_HIDE); 
  }

  //2015/07/26
public:
  void  refresh()
  {
    invalidateAll();
    update();
  }
  
public:
  void  refresh(RECT* rect)
  {
    invalidate(rect);
    update();
  }

public:
  void refresh(int x, int y, int width, int height)
  {
    RECT rect;
    rect.left   = x;
    rect.top    = y;
    rect.right  = x+width;
    rect.bottom = y+height;
    invalidate(&rect);
    update();
  }


public:
  void  updateStyle(Args& args, Arg* arg, int num)
  {
    for(int i = 0; i<num; i++) {
      LONG_PTR style = (LONG_PTR)getWindowLongPtr(GWL_STYLE);
      LONG_PTR val;
      DWORD st = (DWORD)arg[i].value;
      if(args.get(arg[i].name, &val)) {
        if(val) {
          style |= st;
        }
        else {
          if(style & st)
            style ^= st;
        }
        setWindowLongPtr(GWL_STYLE, (LONG_PTR)style);
      }
    }
  }


public:
  Font*  getFont() { 
    return font; 
  }

  virtual void  setFont(HFONT hfont) {
      send(WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE,0));
  }

  virtual void  setFont(Font* font)
  {
    this->font = font;
    if(font) {
      send(WM_SETFONT, (WPARAM)font->getFont(),
          MAKELPARAM(True,0));
    }
  }

  virtual void  setFont(Font& font1)
  {
    font = &font1;
    if(font) {
      send(WM_SETFONT, (WPARAM)font->getFont(),
          MAKELPARAM(True,0));
    }
  }


  void setSysCursor(const TCHAR* name)
  {
    ::SetCursor(::LoadCursor(NULL, name));    
  }

  virtual void getPreferredSize(Dimension& d) 
  {
    preferredSize.get(d);
  }


  virtual void setPreferredSize(Dimension& d) 
  {
    setSize(d.getWidth(), d.getHeight());
    preferredSize.set(d);
  }


public:
  BOOL getDisplayFont(LOGFONT& lf) {
    
    NONCLIENTMETRICS ncm;
    memset(&ncm, 0, sizeof(ncm)); 
    ncm.cbSize = sizeof(ncm); 

    BOOL rc = SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); 
    if (rc) {
      lf = ncm.lfMessageFont; 
    }
    return rc;
  }

  //2009/11/01
public:
  operator HWND(){
    return (HWND)Window::getWindow();
  }

  //2015/08/22
public:
  void activate()
  {
    HWND hwnd = getWindow();
    SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
        SWP_NOMOVE | SWP_NOSIZE);
    SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
        SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
  }

  void bringUp()
  {
    HWND hwnd = getWindow();
    SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
        SWP_NOMOVE | SWP_NOSIZE);
    SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
        SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
    raise();
  }

  void setTopMost()
  {
    HWND hwnd = getWindow();
    SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
        SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
  }
  
  void setTopMost(int x, int y, int width, int height)
  {
    HWND hwnd = getWindow();
    SetWindowPos(hwnd, HWND_TOPMOST, x, y, width, height,
        SWP_SHOWWINDOW);
  }

  //2015/11/26
  void setNoCopyBits()
  {
    HWND hwnd = getWindow();
    SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
        SWP_NOMOVE | SWP_NOSIZE );
    SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
        SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE  |SWP_NOCOPYBITS);
  }
  
  //2015/10/17
  //2016/09/10 Added virtual qualifier
public:
  virtual void postResizeRequest()
  {
    RECT r;
    getClientRect(&r);
    int w = r.right - r.left;
    int h = r.bottom - r.top;
    post(WM_SIZE, 0, MAKELONG(w, h));
  }
  
  virtual void postResizeRequest(int w, int h)
  {
    post(WM_SIZE, 0, MAKELONG(w, h));
  }

  //2016/02/16
  virtual void postRenderRequest()
  {
    post(WM_PAINT, 0, 0);
  }

  //2016/12/04
  virtual void display()
  {
  }
  
  CallbackList& getCallbackList()
  {
    return callbackList;
  }
  
};

}



Last modified: 5 May 2019

Copyright (c) 2009-2019 Antillia.com ALL RIGHTS RESERVED.