/* Class: LoadMDialog  
   Displays all internal modules of a LoadFile in a list box to let the user
   select module to be displayed by the Source Presenter.
   NOTES: This class need to be loaded before the Source/PrjDef classes. */!!

inherit(DialogUtilities, #LoadMDialog, #(loadFile /* current selected LoadFile */
loadModule /* internal load module */
infoTextWindow /* t.w. which contains info */
moduleMax infoMax /* largest entry in list */
moduleWidth infoWidth /* display width */
moduleOffset infoOffset /* display offset */
moduleArray /* module contents */
workText /* file info text collection */
listBoxSelIndex /* index of listbox selection */
), 2, nil)!!

now(class(LoadMDialog))!!

/* Create and a new LoadMDialog object. The dialog's loadFile
  instance variable is the current LoadFile. For example,
  new(FileDialog, currentLoadFile) would create a LoadMDialog object 
  that allow the user select an internal module to be used by the 
  Source Presenter */
Def new(self, theLoadFile | theDlg)
{ 
  theDlg := new(self:Behavior);
  ^init(theDlg, theLoadFile);
}!!

now(LoadMDialog)!!

/* 4/22/1993 15:20 - PRIVATE
  Transfer the information of the selected module to display area.
*/
Def transferInfoInfo(self | p1, p2, temp, tmpDesc)
{
  if loadModule
    infoMax := 0;
    
    /* load file doesn't need to be done here, but need overall max length */
    temp := loadFileName(loadFile);
    infoMax := max(infoMax, size(temp));
    setLoadFile(self, temp);
    
    temp := stringTimeStamp(loadModule);
    infoMax := max(infoMax, size(temp));
    setTime(self, stringTimeStamp(loadModule));
    /* One shot convert address range to text */
    if not(temp := convertAddrRangeToText1(AddressLibClass$Inst,
              addressRange(loadModule), 0, 1, RANGE_BOTH)) then
      temp := ".."
    endif;
    infoMax := max(infoMax, size(temp));
    setAddress(self, temp);
  
    temp := srcPathRef(loadModule);
    infoMax := max(infoMax, size(temp));
    setPath(self, srcPathRef(loadModule));
  endif;  
  ^0;
}!!

/* Re-display the file information either initially, or after hscroll. */
Def refreshInfoDisplay(self | i pos top newWorkText)
{
  newWorkText := new(TextCollection, size(workText));
  /* move scrolled lines to local text collection */
  i := 0;
  loop
  while i < size(workText)
  begin
    /* create work text scrolled to the proper character */
    add(newWorkText, delete(workText[i], 0, infoOffset));
    i := i + 1;
  endLoop;
  
  /* send scrolled text collection to text window */
  setWorkText(infoTextWindow, newWorkText);

  /* set scroll range directly; Actor is hiding that this is a scroll bar */
  localSetScrollRange(self, DLG_SOURCE_BROWSE_TEXT_SCROLL);

  /* update thumb position */
  pos := calculateThumbPosition(self, infoOffset, infoMax, infoWidth);
  localSetScrollPos(self, DLG_SOURCE_BROWSE_TEXT_SCROLL, pos);

  /* redraw text window */
  invalidate(infoTextWindow);

  ^0;
}!!

/* 06/25/93 - PRIVATE
  Transfer the module info from loadFile into local array. 
  NOTES: moduleArray = [ #(moduleName, moduleInfoObj), ...] 
*/
Def transferModuleInfo(self | modulesColl)
{ 
  /* Extract the modules Dict */
  modulesColl := modulesDict(loadFile);
  if not(modulesColl) cor (size(modulesColl) = 0) then    
    ^nil;
  endif;
  moduleMax := 0;  /* module never changes; find max here only */
  
  /* NOTES: 03/16/94
  ** Use the sorted Collection to sort all modules 
  ** Although, the name is "moduleArray", it is a sorted collection.
  */
  if (moduleArray := new(SortedCollection, size(modulesColl))) then
    initWithCompareBlock(moduleArray, 
      { using(e1,e2) 
        e1[0] < e2[0] /* ascending order */
      });    
      
    do (modulesColl, 
      {using(m)
        add(moduleArray, tuple(moduleName(m), m));
        /* find longest (once only) */
        moduleMax := max(moduleMax, size(moduleName(m)));
      }); 
  endif;
  ^GOOD;
}!!

/* Re-display the module listbox either initially, or after hscroll. */
Def refreshModuleListBox(self | i pos top)
{
  /* get current top of list box */
  top := getTopIndex(self, DLG_SOURCE_BROWSE_LB);
  
  /* set redraw off */
  localRedrawOff(self, DLG_SOURCE_BROWSE_LB);
  
  /* fill the list box with modules */
  clearLBText(self, DLG_SOURCE_BROWSE_LB);
  
  /* set scroll range directly; Actor is hiding that this is a scroll bar */
  localSetScrollRange(self, DLG_SOURCE_BROWSE_LB_SCROLL);
  
  /* add its elements in to LB 
  ** NOTES: moduleArray = [ #(moduleName, moduleInfoObj),...]
  */
  i := 0;
  loop
  while i < size(moduleArray)
  begin
    addLBText(self, DLG_SOURCE_BROWSE_LB, delete(moduleArray[i][0], 0, moduleOffset));
    i := i + 1;
  endLoop;
 
  /* set scroll bar position. */
  pos := calculateThumbPosition(self, moduleOffset, moduleMax, moduleWidth);
  localSetScrollPos(self, DLG_SOURCE_BROWSE_LB_SCROLL, pos);
  
  /* re-highlight selection (scroll removes highlight) */
  if listBoxSelIndex 
    sendDlgItemMessage(self, DLG_SOURCE_BROWSE_LB, LB_SETCURSEL,
      listBoxSelIndex, 0L);
  endif;
  
  /* set redraw on prior to last update, which forces repaint. */
  localRedrawOn(self, DLG_SOURCE_BROWSE_LB);

  /* restore top of list box */
  setTopIndex(self, DLG_SOURCE_BROWSE_LB, top);
  
  ^0;
}!!

Def moduleScrollHandle(self)
{
  ^itemHandle(self, DLG_SOURCE_BROWSE_LB_SCROLL);
}!!

Def infoScrollHandle(self)
{
  ^itemHandle(self, DLG_SOURCE_BROWSE_TEXT_SCROLL);
}!!

/* 4/22/1993 14:24 */
Def setLoadFile(self, value)
{
  workText[0] := value;
  ^0;
}!!

Def WM_HSCROLL(self, wP, lP | handle pos)
{
  handle := high(lP);
  pos := low(lP);
 
  if (handle = moduleScrollHandle(self))
    select
      case wP = SB_LINEDOWN
        /* move one position to right if possible */
        if (moduleOffset + moduleWidth < moduleMax)
          moduleOffset := moduleOffset + 1;
          refreshModuleListBox(self);
        endif;
      endCase
      case wP = SB_LINEUP
        /* move one position to left if possible */
        if (moduleOffset > 0)
          moduleOffset := moduleOffset - 1;
          refreshModuleListBox(self);
        endif;
      endCase
      case wP = SB_PAGEDOWN
        /* if room to move, scroll by width - 2, or move to max width */
        if (moduleOffset + moduleWidth < moduleMax)
          moduleOffset := min((moduleOffset + moduleWidth - 2),
            (moduleMax - moduleWidth));
          refreshModuleListBox(self);
        endif;
      endCase
      case wP = SB_PAGEUP
        /* if room to move, scroll by width - 2, or move to 0 */
        if (moduleOffset> 0)
          moduleOffset := max(0, (moduleOffset - moduleWidth + 2));
          refreshModuleListBox(self);
        endif;
      endCase
      case wP = SB_THUMBPOSITION
        /* reverse the set scroll bar position formula */
        moduleOffset := calculateOffset(self, pos, moduleMax, moduleWidth);
        refreshModuleListBox(self);
      endCase
    endSelect;
  else if (handle = infoScrollHandle(self))
    select
      case wP = SB_LINEDOWN
        /* move one position to right if possible */
        if (infoOffset + infoWidth < infoMax)
          infoOffset := infoOffset + 1;
          refreshInfoDisplay(self);
        endif;
      endCase
      case wP = SB_LINEUP
        /* move one position to left if possible */
        if (infoOffset > 0)
          infoOffset := infoOffset - 1;
          refreshInfoDisplay(self);
        endif;
      endCase
      case wP = SB_PAGEDOWN
        /* if room to move, scroll by width - 2, or move to max width */
        if (infoOffset + infoWidth < infoMax)
          infoOffset := min((infoOffset + infoWidth - 2),
            (infoMax - infoWidth));
          refreshInfoDisplay(self);
        endif;
      endCase
      case wP = SB_PAGEUP
        /* if room to move, scroll by width - 2, or move to 0 */
        if (infoOffset> 0)
          infoOffset := max(0, (infoOffset - infoWidth + 2));
          refreshInfoDisplay(self);
        endif;
      endCase
      case wP = SB_THUMBPOSITION
        /* reverse the set scroll bar position formula */
        infoOffset := calculateOffset(self, pos, infoMax, infoWidth);
        refreshInfoDisplay(self);
      endCase
    endSelect;
    endif;
  endif;
}!!

/* 4/22/1993 14:24 */
Def setPath(self, value)
{
  workText[3] := value;
  ^0;
}!!

/* 4/22/1993 14:24 */
Def setAddress(self, value)
{
  workText[2] := value;
  ^0;
}!!

/* 4/22/1993 14:24 */
Def setTime(self, value)
{
  workText[1] := value;
  ^0;
}!!

/* create text window; directly overlay the text template */
Def initTextWindow(self |
    templateAbsRect templateRelRect addrPnt absTL absBR relTL relBR)
{
  /* create absolute and relative rectangles and points */  
  templateAbsRect := new(Rect);
  templateRelRect := new(Rect);
  absTL := new(Point);
  absBR := new(Point);
  relTL := new(Point);
  relBR := new(Point);
  
  /* get coordinates of text template */
  Call GetWindowRect(itemHandle(self, DLG_SOURCE_BROWSE_TEXT_TEMPLATE),
    templateAbsRect);
  
  /* get points from rectangle */
  absTL := origin(templateAbsRect);
  absBR := corner(templateAbsRect);
  
  /* map points from absolute (window) to relative (client) */
  relTL := screenToClient(self, absTL);
  relBR := screenToClient(self, absBR);
  
  /* place coordinates into relative rectangle */
  setOrigin(templateRelRect, relTL);
  setCorner(templateRelRect, relBR);

  infoTextWindow := newStyle(TextWindow, self, nil, nil, templateRelRect,
      DLG_SOURCE_BROWSE_TEXT, WS_CHILD bitOr WS_BORDER);
  
  /* set LOCAL work text to contain 4 items; sent to infoTextWindow
     later by refreshInfoDisplay. */
  workText := new(TextCollection, 4);
  add(workText, "");
  add(workText, "");
  add(workText, "");
  add(workText, "");
  
  show(infoTextWindow, 1);
  
  ^0;
}!!

/* 06/25/93 - 
  Dialog box command processing. 
*/
Def command(self, wp, lp)
{
  select
    case wp = IDCANCEL 
      is end(self, IDCANCEL); 
    endCase
     
    case wp = IDOK 
      if loadModule
        end(self, IDOK); /* make sure that user select a module */
      else
        /* Since there is no loadModule selected - return cancel */  
        end(self, IDCANCEL); 
      endif;  
    endCase
    case wp = IDHELP
      is contextNumber(TheHelpObject, hWnd, HE_DLGR_LOAD_MODULE);
    endCase

    /* User select module - display module's internal information */
    case (high(lp) = LBN_SELCHANGE) 
      listBoxSelIndex := getLBSel(self, DLG_SOURCE_BROWSE_LB);
      /* NOTES: moduleArray = [#(moduleName, moduleInfoObj), ...] */
      if (loadModule := moduleArray[listBoxSelIndex][1]) then
        transferInfoInfo(self);
        refreshInfoDisplay(self);
      endif;          
    endCase
    
    case (high(lp) = LBN_DBLCLK) 
      listBoxSelIndex := getLBSel(self, DLG_SOURCE_BROWSE_LB);
      /* NOTES: moduleArray = [#(moduleName, moduleInfoObj), ...] */
      if (loadModule := moduleArray[listBoxSelIndex][1]) then
        end(self, IDOK);
      endif;          
    endCase
      
  endSelect;
  ^GOOD;
}!!

/* 2/12/1992 15:51 - PUBLIC
  Return the selected module */
Def getSelModule(self)
{ 
  ^loadModule; 
}
!!

/* 06/25/93 - PRIVATE
  Initialize LoadModule Dialog box and its instance variables 
*/
Def init(self, theLoadFile)
{ 
  init(self:ancestor);    
  loadFile    := theLoadFile;
  loadModule  := nil; /* return selected module descriptor */  
  infoWidth   := 12;
  moduleWidth := 12;
}
!!

/* 06/25/93 - PRIVATE
  By returning a 1 from the INITDIALOG message, we
  are telling MS-Windows to set the input focus to
  first tabstop item. (See MS-Windows Reference). */
Def initDialog(self, wP, lP)
{
  showWaitCurs();

  moduleOffset := 0;
  infoOffset := 0;
  
  registerF1Help(CLIULibraryClass$Inst, HI_DLGR_LOAD_MODULE,
     getHWnd(self), HE_DLGR_LOAD_MODULE);
     
  initTextWindow(self);
  /* set up module info, display - If failed disable the listbox item */
  if not(transferModuleInfo(self)) then
    disableItem(self, DLG_SOURCE_BROWSE_LB);
    showOldCurs();
    ^1;
  endif;
  /* Refresh the listbox */
  refreshModuleListBox(self);
  
  /* select top item in list box for info display */
  listBoxSelIndex := 0;
  sendDlgItemMessage(self, DLG_SOURCE_BROWSE_LB, LB_SETCURSEL,
    listBoxSelIndex , 0L);
  /* NOTES: moduleArray = [ #(moduleName, moduleInfoObj),...] */  
  loadModule := moduleArray[listBoxSelIndex][1];
  
  /* set up file info, display */
  transferInfoInfo(self);  
  refreshInfoDisplay(self);
  
  showOldCurs();
  ^1;  /* set focus to first tabstop element */
}!!
