/* The ComboBox class creates and manages ComboBox
  controls.  A ComboBox is a pre-defined window type
  with two elements, an edit control and a listbox.
  This class provides the same high-level interface
  provided by its ancestor for managing the listbox
  portion and includes additional methods for the edit
  control. There is a variety of different types
  of ComboBoxes, so the generic "new" method takes a
  style value as one of the arguments. */!!

inherit(ListBox, #ComboBox, nil, 2, nil)!!

now(class(ComboBox))!!

/* Create a new ComboBx object in Actor and Windows.
  Parent passes itself, the control ID, the location
   rectangle, and the style. */
Def new(self, id, par, rect, style | theCB)
{ theCB := new(self:Behavior); /* create object */
  setVars(theCB, id, par, rect);
  create(theCB, nil, "ComboBox",
    style bitOr WS_CHILD);
  if handle(theCB) = 0
  then alert(System, self, #wCreateError);
  endif;
  ^theCB;
}!!

/* Create a new ComboBox object in Actor and Windows.
  Parent passes itself, the control ID, and location
  rectangle. The DropDown style combobox displays
  the listbox only on demand. */
Def newDropDown(self, id, par, rect)
{ ^new(self, id, par, rect,
   CBS_DROPDOWN bitOr CBS_SORT bitOr WS_VSCROLL);
}!!

/* Create a new ComboBox object in Actor and Windows.
  Parent passes itself, the control ID, and location
  rectangle. The DropDownList style combobox displays
  the listbox when the user selects it. */
Def newDropDownList(self, id, par, rect)
{ ^new(self, id, par, rect,
   CBS_DROPDOWNLIST bitOr CBS_SORT bitOr WS_VSCROLL);
}!!

/* Create a new ComboBox object in Actor and Windows.
  Parent passes itself, the control ID, and location
  rectangle. The Simple style combobox displays a listbox
  at all times. */
Def newSimple(self, id, par, rect)
{ ^new(self, id, par, rect,
   CBS_SIMPLE bitOr CBS_SORT bitOr WS_VSCROLL);
}!!

now(ComboBox)!!

/* Add aStr to the ListBox, maintaining sorted order, and
  return its index. */
Def addString(self, aStr)
{ ^sendMessage(self, CB_ADDSTRING, 0, asciiz(aStr));
}!!

/* Clear the contents of the list in the ComboBox. */
Def clearList(self)
{ selStr := selIdx := nil;
  ^sendMessage(self, CB_RESETCONTENT, 0, 0);
}!!

/* Remove the indexed item from the listbox. */
Def deleteString(self, idx)
{ ^sendMessage(self, CB_DELETESTRING, idx, 0L);
}!!

/* Return the number of items in the list. */
Def getCount(self | idx)
{ idx := sendMessage(self, CB_GETCOUNT, 0, 0);
 ^(idx <> CB_ERR) cand idx;
}!!

/* Return the index of whatever item is
  currently selected and set selIdx.
  Return nil if no item is selected. */
Def getSelIdx(self | idx )
{ idx := sendMessage(self, CB_GETCURSEL, 0, 0);
 if idx = CB_ERR
 then ^nil;
 endif;
 ^selIdx := idx;
}!!

/* Return the selected string.  Return nil if none
  is selected. */
Def getSelString(self | idx, ans)
{ if idx := getSelIdx(self)
  then sendMessage(self, CB_GETLBTEXT, idx,
    ans := new(String, sendMessage(self, CB_GETLBTEXTLEN, idx, 0) + 1));
    ^removeNulls(ans);
  endif;
  ^nil;
}!!

/* Return the string at idx.  Nil is returned if
  there is an error. */
Def getString(self, idx | len, str)
{ if ((len := sendMessage(self,CB_GETLBTEXTLEN, idx, 0)) <> LBN_ERR)
    cand (sendMessage(self,  CB_GETLBTEXT , idx,
    str := new(String, len + 1)) <> CB_ERR)
  then ^removeNulls(str);
  endif;
  ^nil;
}!!

/* Add aStr to the list at the specified idx,
  overriding the sorted order and return its index. If
  idx=-1, aStr is added to end of list. */
Def insertString(self, aStr, idx)
{ ^sendMessage(self, CB_INSERTSTRING, idx, asciiz(aStr));
}!!

/* Select the specifed string if possible, and set
  and return selIdx. Return nil if selecting aStr
  doesn't work, and don't reset selIdx. */
Def selectString(self, aStr | idx)
{ if aStr cand ((idx := sendMessage(self,
    CB_SELECTSTRING, -1, asciiz(aStr))) <> CB_ERR)
  then ^selIdx := idx;
  endif;
  ^nil;
}!!

/* Set the current selection to idx. */
Def setCurSel(self, idx)
{ ^sendMessage(self, CB_SETCURSEL, idx, 0);
}!!

/* Set the instance variables of the ComboBox. */
Def setVars(self, id, par, rect)
{ setVars(self:ancestor, id, par);
  cRect := rect;
}!!

/* Show or hide the list depending on whether the
 show argument is true or false, respectively. */
Def showList(self, show)
{ ^sendMessage(self, CB_SHOWDROPDOWN, (show cand 1) cor 0, 0);
}!!

/* ComboBoxes need to execute the default
 window proc for WM_COMMAND messages. */
Def WM_COMMAND(self, wp, lp)
{ command(self, wp, lp);
  ^execWindowProc(self, #WM_COMMAND, wp, lp);
}!!
