SOL9 2.0 Class: ComboBox

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

Source code

/******************************************************************************
 *
 * Copyright (c) 1999-2012 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.
 *
 *
 *  ComboBox.h
 *
 *****************************************************************************/

// SOL++2000
// 2000/02/18
// 2001/03/19 Added getPreferredSize method.
// 2001/03/29 Added getControlHeight, setControlHeight methods.
// 2001/03/29 Added static variables itemsListDelim, heightMargin.

// 2009/09/22 Added getString method
// 2012/06/22

#pragma once

#include <sol\Primitive.h>
#include <sol\WString.h>
#include <sol/StringConverter.h>

namespace SOL {

class ComboBox :public Primitive {

private:
  // 2001/03/29 Added CBS_AUTOHSCROLL style
  static const long STYLE = (const long)(WS_TABSTOP|WS_VSCROLL|CBS_NOINTEGRALHEIGHT|CBS_AUTOHSCROLL);

  static const TCHAR itemsListDelim = '\n';

  static const int heightMargin = 2;

  static int stylesCount()
  {
    int count = 0;
    styles(&count);
    return count;
  }

  static Arg*  styles(int* count=NULL)
  {
    static  Arg _styles[] = {
    {XmNsortItems,        CBS_SORT},
    {XmNdisableNoScroll, CBS_DISABLENOSCROLL},
    {XmNoemConvert,      CBS_OEMCONVERT}
    };
    if (count) {
      *count = XtNumber(_styles);
    }
    return _styles;
  }

public:
  ComboBox():Primitive() { }

  ComboBox(View* parent, HWND hwnd)
    :Primitive(parent, hwnd) { }

public:
  //2012/06/22
  ComboBox(View* parent, const TCHAR* name, Args& args)
  :Primitive()
  {
    create(parent, name, args);
  }

public:
  virtual Boolean create(View* parent, const TCHAR* name, Args& args)
  {
    Boolean rc = False;
    rc = Primitive::create(parent, name, 
      args.set(styles(), stylesCount())
          .set(XmNpredefined, TRUE)
          .set(XmNstyle, (LONG_PTR)STYLE)
        .set(XmNuseDefaultFont, _T("true"))
          .set(XmNclassName, _T("ComboBox")));

    setValues(args);

    return rc;  
  }

public:
  Arg* getCallbackTable(int* num)
  {
    static Arg table[] = {
    {XmNcloseUpCallback,    CBN_CLOSEUP},
     {XmNdefaultActionCallback,  CBN_DBLCLK},
     {XmNdropDownCallback,    CBN_DROPDOWN},
    {XmNeditChangeCallback,    CBN_EDITCHANGE},
    {XmNeditUpdateCallback,    CBN_EDITUPDATE},
    {XmNerrorSpaceCallback,    (LONG_PTR)CBN_ERRSPACE},

    {XmNkillFocusCallback,    CBN_KILLFOCUS},
    {XmNselChangeCallback,    CBN_SELCHANGE},
    {XmNselEndCancelCallback,  CBN_SELENDCANCEL},
    {XmNselEndOkCallback,    CBN_SELENDOK},
    {XmNsetFocusCallback,    CBN_SETFOCUS}
    };

    *num = XtNumber(table);
    return table;
  }

public:
  void getValues(Args& args)
  {
    Primitive::getValues(args);

    getStyle(args, styles(), stylesCount());

    LONG_PTR* val = (LONG_PTR*)args.get(XmNitemsList);
    if(val) {
      int buffLen = 0;
      int count  = getCount();
      // 2001/03/31
      // Compute the length of string buffer to store all 
      // item-texts separated with a new line .
      for(int n = 0; n< count; n++) {
        buffLen = buffLen + getLBTextLen(n) + 1; //strlen("\n");  
      }   

      TCHAR* list = new TCHAR[buffLen];
      *list      = NULL;
      TCHAR* buff = list;
      for(int i = 0; i< count; i++) {
        int len = getLBTextLen(i);
        getLBText(i, buff);
        buff += len;
      
        if(i < count -1) {
          *buff = itemsListDelim;
        }
        buff++;
      }
      *buff = ZERO;
      *val  = (LONG_PTR)list;
    }
  }

public:
  // 2001/03/29
  void setValues(Args& args)
  {  
    LONG_PTR v;
    if (!args.get(XmNwidth, &v) ) {
      args.set(XmNwidth, 100);
    }
    if (!args.get(XmNheight, &v) ) {
      args.set(XmNheight, 100);
    }
  

    Primitive::setValues(args);

    updateStyle(args, styles(), stylesCount());

    /*
    */
  
    LONG_PTR  val;
    if (args.get(XmNmaxLength, &val))
      limitText((int)val);

    if (args.get(XmNlabelString, &val))
      setText((TCHAR*)val);

    // XmNitems & XmNitemCount;
    TCHAR** items = NULL;
    int     count = 0;
    if (args.get(XmNitemCount, &val))
      count = (int)val;
    if (args.get(XmNitems, &val))
      items = (TCHAR**)val;
    if (count> 0 && items) {
      resetContent();
      for(int i = 0; i<count; i++) {
        addString(items[i]);
      }
    }

    // XmNitemsList
    TCHAR* list = NULL;
    if (args.get(XmNitemsList, &val)) {
      resetContent();
      TCHAR* item = (TCHAR*)val;
      size_t slen = strlen(item)+1;
      list = new TCHAR[slen];
      strcpy_s(list, slen, item);
    }

    if (list) {
      TCHAR* str = list;
      TCHAR* ptr = list;
      while(*ptr) {
        if(*ptr == itemsListDelim) {  //2001/04/01
          *ptr++ = NULL;
          addString(str);
          str = ptr;
        }
        else {
          ptr++;
        }
      }
      if(str)  addString(str);
      if(list) delete[] list;
    }
  }

public:
  // List up long file names.
  void findFiles(DWORD attr, const TCHAR* pattern)
  {
    WIN32_FIND_DATA data;
    HANDLE hf = ::FindFirstFile(pattern, &data);
    if(hf != INVALID_HANDLE_VALUE) {
      do {
        if(data.dwFileAttributes & attr) {
          addString((TCHAR*)data.cFileName);
        }      
      } while(::FindNextFile(hf, &data));
      ::FindClose(hf);
    }
  }

public:
  void findFiles(const TCHAR* pattern)
  {
    DWORD attr = FILE_ATTRIBUTE_ARCHIVE|
    FILE_ATTRIBUTE_DIRECTORY|
    FILE_ATTRIBUTE_COMPRESSED|
    FILE_ATTRIBUTE_HIDDEN|   
    FILE_ATTRIBUTE_NORMAL|  
    FILE_ATTRIBUTE_READONLY| 
    FILE_ATTRIBUTE_SYSTEM;
    ComboBox::findFiles(attr, pattern);  
  }

public:
  // Find all subdirectories under dir.
  // Give a string such as "c:\\windows"  for dir.
  void findDirectories(const TCHAR* dir)
  {
    TCHAR pattern[_MAX_PATH];
    _stprintf_s(pattern, CountOf(pattern), _T("%s\\*.*"), dir);
    findFiles(FILE_ATTRIBUTE_DIRECTORY, pattern);
  }


// 2001/03/19
public:
  void getPreferredSize(Dimension& d)
  {
    int w, h;
    getSize(w, h);

    LONG style   = (LONG)getWindowLongPtr(GWL_STYLE);
    if ((style & CBS_DROPDOWN) ||
      (style & CBS_DROPDOWNLIST )) {
      h = getControlHeight() + heightMargin;
    }
    d.set(w, h);
  }


  int   addString(const TCHAR* string) {
      return (int)send(CB_ADDSTRING, 0, (LPARAM)string);
  }

  //2017/07/30
  int   addString(const WString* string) {
    StringConverter converter;
    StringT<char> mb;
    converter.toMultiByte((const wchar_t*)(*string), mb);
     return (int)send(CB_ADDSTRING, 0, (LPARAM)(const char*)mb );
  }

  const TCHAR*  defaultCallbackName() { 
    return XmNdefaultActionCallback; 
  }

  void clear()
  {
    resetContent();
  }

  int   deleteString(int indx) {
      return (int)send(CB_DELETESTRING, indx, 0L);
  }
  int    dir(int attr, const TCHAR* string) {
      return (int)send(CB_DIR, attr, (LPARAM)string);
  }

  int    findString(int indx, TCHAR* string) {
      return (int)send(CB_FINDSTRING, indx, (LPARAM)string);
  }
  int    findStringExact(int indx, TCHAR* string) {
      return (int)send(CB_FINDSTRINGEXACT, indx, (LPARAM)string);
  }
  
//  Arg*  getCallbackTable(int* num);

  int   getCount() {
      return (int)send(CB_GETCOUNT, 0, 0L);
  }

  int    getCurSel() {
      return (int)send(CB_GETCURSEL, 0, 0L);
  }

  int    getDroppedControlRect(RECT* rect) {
      return (int)send(CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)rect);
  }

  int    getDroppedState() {
      return (int)send(CB_GETDROPPEDSTATE, 0, 0L);
  }

  LRESULT  getEditSel() {
      return send(CB_GETEDITSEL, 0, 0L);
  }

  int    getExtendedUI() {
      return (int)send(CB_GETEXTENDEDUI, 0, 0L);
  }

  LRESULT  getItemData(int indx) {
      return send(CB_GETITEMDATA, indx, 0L);
  }

  int    getItemHeight(int indx) {
      return (int)send(CB_GETITEMHEIGHT, indx, 0L);
  }

  // 2001/03/29
  int     getControlHeight() {
            //Return the height of the edit control(or static-text) portion of the combo box.
      return (int)send(CB_GETITEMHEIGHT, (WPARAM)-1, 0L);
  }

  bool  getString(int indx, String& string)
  {
    bool rc = false;
    int len = getLBTextLen(indx);

    if (len >0) {
      TCHAR* buffer = new TCHAR[len+1];
      memset(buffer, (TCHAR)0, len+1);
      if (getLBText(indx, buffer)) {

        string.shallowCopy(buffer);
        rc = true;
      }
    }
    return rc;
  }

  bool  getString(int indx, WString& string)
  {
    bool rc = false;
    int len = getLBTextLen(indx);

    if (len >0) {
      wchar_t* buffer = new wchar_t[len+1];
      memset(buffer, (wchar_t)0, len+1);
      if (send(CB_GETLBTEXT, indx, (LPARAM)buffer)) {

        string.shallowCopy(buffer);
        rc = true;
      }
    }
    return rc;
  }
  
  int    getLBText(int indx, TCHAR* buffer) {
      return (int)send(CB_GETLBTEXT, indx, (LPARAM)buffer);
  }

  int    getLBTextLen(int indx) {
      return (int)send(CB_GETLBTEXTLEN, indx, 0L);
  }

//  void  getValues(Args& args);

  int   insertString(int indx, TCHAR* string) {
      return (int)send(CB_INSERTSTRING, indx, (LPARAM)string);
  }
  int    limitText(int len) {
      return (int)send(CB_LIMITTEXT, len, 0L);
  }
  void  resetContent() {
      send(CB_RESETCONTENT, 0, 0L);
  }

  int    selectString(int indx, TCHAR* string) {
      return (int)send(CB_SELECTSTRING, indx, (LPARAM)string);
  }

  int    setCurSel(int indx) {
      return (int)send(CB_SETCURSEL, indx, 0L);
  }
  
  int    setEditSel(int start, int end) {
      return (int)send(CB_SETEDITSEL, 0, MAKELONG(start, end));
  }
  int    setExtendedUI(int flag) {
      return (int)send(CB_SETEXTENDEDUI, flag, 0L);
  }
  int    setItemData(int indx, LONG data) {
      return (int)send(CB_SETITEMDATA, indx, data);
  }
  int    setItemHeight(int indx, int height) {
      return (int)send(CB_SETITEMHEIGHT, indx, (LPARAM)height);
  }
  int     setControlHeight(int height) {
      return (int)send(CB_SETITEMHEIGHT, (WPARAM)-1, (LPARAM)height);
  }

//  void  setValues(Args& args);  

  void  showDropDown(int showCmd) {
      send(CB_SHOWDROPDOWN, showCmd, 0L);
  }

  LRESULT   getLocale() {
      return send(CB_GETLOCALE, 0, 0L);
  }

  LRESULT   setLocale(long localeId) {
       return send(CB_SETLOCALE, (WPARAM)localeId, 0L);
  }

  String getCurrentSelection()
  {
    int i = getCurSel();
    if (i >=0 ) {
      TCHAR text[MAX_PATH];

      getLBText(i, text);
      return String(text);
    } else {
      throw IException("Not item selected");
    }
  }
  
  int    setCurrentSelection(int indx) {
      return (int)send(CB_SETCURSEL, indx, 0L);
  }

  void  setDroppedWidth(int width)
  {
    send(CB_SETDROPPEDWIDTH, width, 0);
  }
  
};

}


Last modified: 5 May 2019

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