SOL9 2.0 Class: ListBox

 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.
 *
 *
 *  ListBox.h
 *
 *****************************************************************************/

// SOL++2000
// 2000.02.18
// 2012/06/25

#pragma once

#include <sol\Primitive.h>


namespace SOL {

class ListBox :public Primitive {
private:
  //2009/11/07 For findAllFiles method
  bool scanning;

private:

  static const long STYLE = (WS_TABSTOP|WS_BORDER|LBS_NOTIFY|WS_HSCROLL|WS_VSCROLL|\
        LBS_NOINTEGRALHEIGHT);

  static const TCHAR itemsListDelim = '\n';

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

  static Arg* styles(int* count=NULL)
  {
    static Arg _styles[] = {
    {XmNdisableNoScroll,   LBS_DISABLENOSCROLL},
    {XmNextendedSel,       LBS_EXTENDEDSEL},
    {XmNmultiColumn,       LBS_MULTICOLUMN},
    {XmNmultipleSel,       LBS_MULTIPLESEL},
    {XmNsortItems,         LBS_SORT},
    {XmNuseTabStops,       LBS_USETABSTOPS},
    {XmNwantKeyboardInput, LBS_WANTKEYBOARDINPUT},
    };

    if (count){
      *count = XtNumber(_styles);
    }
    return _styles;
  }


public:
  ListBox():Primitive() { }

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

public:
  //2012/06/25
  ListBox(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 = Primitive::create(parent, name, 
      args.set(styles(), stylesCount())
          .set(XmNpredefined, TRUE)
          .set(XmNstyle,     (LONG_PTR)STYLE)
          .set(XmNexStyle,   (LONG_PTR)WS_EX_CLIENTEDGE)
        .set(XmNuseDefaultFont, _T("true"))
          .set(XmNclassName, _T("ListBox")));

    setValues(args);

    return rc;
  }

public:
  Arg* getCallbackTable(int* num)
  {
    static Arg table[] = {
    {XmNdefaultActionCallback,   LBN_DBLCLK},
    {XmNerrorSpaceCallback,    (LONG_PTR)LBN_ERRSPACE},
    {XmNkillFocusCallback,    LBN_KILLFOCUS},
    {XmNselCancelCallback,    LBN_SELCANCEL},
     {XmNselChangeCallback,    LBN_SELCHANGE},
     {XmNsetFocusCallback,    LBN_SETFOCUS},
     };

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

public:
  int  getCurText(TCHAR* buffer) 
  {
    if(buffer) {
      *buffer = ZERO;
      int indx = getCurSel();
      if(indx != LB_ERR) {
        return getText(indx, buffer);
      }
      else {
        return 0;
      }
    }
    return 0;
  }

public:
  TCHAR* getCurText()
  {
    TCHAR* text = NULL;

    int indx = getCurSel();
    if(indx != LB_ERR) {
      int len = getTextLen(indx);
      text = new TCHAR[len+1];
      getText(indx, text);
    }
    return text;
  }

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();
      for(int n = 0; n< count; n++) {
        buffLen = buffLen + getTextLen(n) + 1; //strlen("\n");
      }

      TCHAR* list = new TCHAR[buffLen];
      *list      = NULL;
      TCHAR* buff = list;

      for(int i = 0; i< count; i++) {
        int len = getTextLen(i);
        getText(i, buff);
        buff += len;
        if(i < count -1) {
          *buff  = itemsListDelim;
        }
        buff++;
      }
      *buff = ZERO;

      *val  = (LONG_PTR)list;
    }
  }

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

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

    LONG_PTR  val;
    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* s = (TCHAR*)val;
      size_t slen = strlen(s)+1;
      list = new TCHAR[slen];
      strcpy_s(list, slen, s);
    }
    if (list) {
      TCHAR* str = list;
      TCHAR* ptr = list;
      while(*ptr) {
        if(*ptr == itemsListDelim) {
          *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;
    ListBox::findFiles(attr, pattern);  
  }

private:
  //2009/11/07
  void dispatchMessage()
  {
    MSG msg;
    
    while(
      PeekMessage (&msg,NULL,0,0,PM_REMOVE)) {
      SleepEx(10, TRUE);
      if (msg.message == WM_QUIT) {
        scanning = false;
        //Repost WM_QUIT message to your application message queue.
        PostMessage(NULL, WM_QUIT, 0, 0);
        break;
      }
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }

public:
  //2009/11/06
  //2009/11/06
  // List up all file name having an extension of ext.
  void findAllFiles(const TCHAR* dir, const TCHAR* ext)
  {
    if (dir == NULL || ext == NULL) {
      return;
    }

    setRedraw(FALSE);
    clear();
    scanning = true;
    
    findAllFilesRecursively(dir, ext);
    scanning = false;
    
    setRedraw(TRUE);
  }

public:
  bool isScanning()
  {
    return scanning;
  }

public:
  void stopScanning()
  {
    scanning = false;
  }

public:
  //2009/11/06
  // List up all file name having an extension of ext.
  void findAllFilesRecursively(const TCHAR* dir, const TCHAR* ext)
  {
    if (scanning == false) {
      return;
    }

    setRedraw(FALSE);

    WIN32_FIND_DATA data;
    TCHAR* path = new TCHAR[MAX_PATH];
    _stprintf_s(path, MAX_PATH, _T("%s\\%s"), dir, _T("*"));
    
    HANDLE hf = ::FindFirstFile(path, &data);
    if(hf != INVALID_HANDLE_VALUE) {
      do {
        dispatchMessage();
        if (scanning == false) {
          break;
        }
        if (!(strcmp(data.cFileName, _T(".")) == 0 ||
          strcmp(data.cFileName, _T("..")) == 0)) {
    
          TCHAR* fullPath = new TCHAR[MAX_PATH];
          _stprintf_s(fullPath, MAX_PATH, _T("%s\\%s"), dir, data.cFileName);

          if(String::endsWithIgnoreCase(data.cFileName, ext)) {
            addString((TCHAR*)fullPath);
          }
          // Recursively call findAllFile provided fullPath were a directory
          if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            findAllFilesRecursively(fullPath, ext); 
          }
          delete [] fullPath;
        }
      } while(::FindNextFile(hf, &data));
      ::FindClose(hf);
    }
    delete [] path;

    setRedraw(TRUE);
  }

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);
  }

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

  // 1999.09.23
  void  clear() {
      send(LB_RESETCONTENT, 0, 0L);
  }

  const TCHAR*  defaultCallbackName() { 
    return XmNdefaultActionCallback; 
  }
  
  int   deleteString(int indx) {
      return (int)send(LB_DELETESTRING, indx, 0L);
  }

  int    dir(int attr, const TCHAR* string) {
      return (int)send(LB_DIR, attr, (LPARAM)string);
  }

  int    findString(int indx, const TCHAR* string) {
      return (int)send(LB_FINDSTRING, indx, (LPARAM)string);
  }

  int    findStringExact(int indx, const TCHAR* string) {
      return (int)send(LB_FINDSTRINGEXACT, indx, (LPARAM)string);
  }

  int   getCaretIndex() {
      return (int)send(LB_GETCARETINDEX, 0, 0L);
  }

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

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

  int    getHorizontalExtent() {
      return (int)send(LB_GETHORIZONTALEXTENT, 0, 0L);
  }

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

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

  LRESULT    getItemRect(int indx, LPRECT rect) {
      return (int)send(LB_GETITEMRECT, indx, (LPARAM)rect);
  }

  int    getSel(int indx) {
      return (int)send(LB_GETSEL, indx, 0L);
  }

  int    getSelCount() {
      return (int)send(LB_GETSELCOUNT, 0, 0L);
  }

  int    getSelItems(int max, int array[]) {
      return (int)send(LB_GETSELITEMS, max, (LPARAM)array);
  }

  int   getText(int indx, TCHAR* buffer) {
      return (int)send(LB_GETTEXT, indx, (LPARAM)buffer);
  }

  int   getTextLen(int indx) {
      return (int)send(LB_GETTEXTLEN, indx, 0L);
  }

  int    getTopIndex() {
      return (int)send(LB_GETTOPINDEX, 0, 0L);
  }

  int   insertString(int indx, const TCHAR* string) {
      return (int)send(LB_INSERTSTRING, indx, (LPARAM)string);
  }

  void  resetContent() {
      send(LB_RESETCONTENT, 0, 0L);
  }

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

  int    selItemRange(int sel, int first, int last) {
      return (int)send(LB_SELITEMRANGE, sel, MAKELPARAM(first,last));
  }

  void  setCaretIndex(int indx, int scroll) {
      send(LB_SETCARETINDEX, indx, MAKELPARAM(scroll, 0));
  }

  void  setColumnWidth(int width) {
      send(LB_SETCOLUMNWIDTH, width, 0L);
  }

  int    setCurSel(int indx) {
      return (int)send(LB_SETCURSEL, indx, 0L);
  }

  void  setHorizontalExtent(int width) {
      send(LB_SETHORIZONTALEXTENT, width, 0L);
  }

  int    setItemData(int indx, LPARAM data) {
      return (int)send(LB_SETITEMDATA, indx, data);
  }

  int    setItemHeight(int indx, int height) {
      return (int)send(LB_SETITEMHEIGHT, indx, MAKELPARAM(height,0));
  }

  int    setSel(int sel, int indx) {
      return (int)send(LB_SETSEL, sel, MAKELPARAM(indx, 0));
  }

  int    setTabStops(int num, int pos[]) {
      return (int)send(LB_SETTABSTOPS, num, (LPARAM)pos);
  }

  int    setTopIndex(int indx) {
      return (int)send(LB_SETTOPINDEX, indx, 0L);
  }
//  void  setValues(Args& args);

  int   getAnchorIndex() {
       return (int)send(LB_GETANCHORINDEX, 0, 0L);
  }

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

  void   setAnchorIndex(int indx) {
       send(LB_SETANCHORINDEX, (WPARAM)indx, 0L);
  }

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

}



Last modified: 5 May 2019

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