/* * Descent 3 * Copyright (C) 2024 Parallax Software * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . --- HISTORICAL COMMENTS FOLLOW --- * $Logfile: /DescentIII/Main/editor/GrListBox.cpp $ * $Revision: 1.1.1.1 $ * $Date: 2003-08-26 03:57:38 $ * $Author: kevinb $ * * New graphical listbox * * $Log: not supported by cvs2svn $ * * 8 6/10/98 1:57p Samir * fixed some listbox problems. * * 7 6/10/98 12:18p Matt * Added hack to fix bug until Samir can fix it for real. * * 6 2/10/98 3:16p Craig * Samir * * 5 9/30/97 5:35p Samir * Fixed hangup bug when masking out textures. * * 4 8/26/97 11:39a Samir * Check editor_active to see whether editor graphics are active or not. * * 3 8/26/97 10:49a Samir * Fixed some small bugs with the scroll bar. * * $NoKeywords: $ */ // GrListBox.cpp : implementation file // #include "stdafx.h" #include "editor.h" #include "GrListBox.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CGrListBox CGrListBox::CGrListBox() { items_max_row = 0; items_per_row = 0; m_ListLen = 0; m_ListItem = 0; m_SurfDimension = 0; m_ItemSel = -1; // -1 because item number can be 0 and a valid item. m_HitX = 0; m_HitY = 0; m_CheckHit = false; m_IsItemSelInBox = false; } CGrListBox::~CGrListBox() { } BOOL CGrListBox::Create(CWnd *parent_wnd, int id, const RECT& rect, int surf_dim, bool selbox) { m_SurfDimension = surf_dim; m_SelectionBox = selbox; return CWnd::Create(NULL, "GrListBox", WS_CHILD | WS_VISIBLE | WS_VSCROLL, rect, parent_wnd, id); } void CGrListBox::SelectItem(int item) { // don't do a damn thing if the item selected equals the requested selected item if (item != m_ItemSel) { m_ItemSel = item; OnItemSelected(item); ListBoxProc(false); // update list box data but don't draw yet. // scroll window until item wanted is in view. if (m_IsItemSelInBox == false) { //SAMIR: fix this!! int count=0; while (m_ListItem < m_ItemSel && (++count < 100)) if (RowDown(1,false)) break; while (m_ListItem > m_ItemSel && (++count < 100)) if (RowUp(1,false)) break; } CWnd::Invalidate(); } } void CGrListBox::SetItemFirst(int item) { m_ListItem = item; } int CGrListBox::GetItemFirst() const { return m_ListItem; } BEGIN_MESSAGE_MAP(CGrListBox, CWnd) //{{AFX_MSG_MAP(CGrListBox) ON_WM_LBUTTONDOWN() ON_WM_PAINT() ON_WM_VSCROLL() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CGrListBox message handlers void CGrListBox::OnPaint() { CPaintDC dc(this); // device context for painting ListBoxProc(true); } void CGrListBox::OnLButtonDown(UINT nFlags, CPoint point) { int old_sel; m_CheckHit = true; m_HitX = point.x; m_HitY = point.y; // should we have to redraw box if we haven't changed a selection? old_sel = m_ItemSel; ListBoxProc(false); if (old_sel != m_ItemSel) CWnd::Invalidate(FALSE); CWnd::OnLButtonDown(nFlags, point); } void CGrListBox::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { SCROLLINFO si; int cur_pos, new_pos; GetScrollInfo(SB_VERT, &si, SIF_ALL); cur_pos = m_ScrollPos; switch (nSBCode) { case SB_LINEDOWN: new_pos = cur_pos + 1; break; case SB_LINEUP: new_pos = cur_pos - 1; break; case SB_THUMBPOSITION: new_pos = nPos; break; case SB_THUMBTRACK: new_pos = nPos; break; case SB_PAGEDOWN: new_pos = cur_pos + si.nPage; break; case SB_PAGEUP: new_pos = cur_pos - si.nPage; break; default: new_pos = cur_pos; } if (new_pos < 0) new_pos = 0; if (new_pos > (int)(si.nMax - si.nPage+1)) new_pos = (int)(si.nMax - si.nPage+1); // if (new_pos == 0) RowUp((cur_pos-new_pos)+1); // list up until start of list. prevents missing items if (new_pos != cur_pos) { // ok, new_pos will be an index into the listbox, NOT the texture list. // so we will get the number of texture rows we went up or down and change // tex_start accordingly. SCROLLINFO si; // mprintf((0, "scroll new_pos = %d. original_pos = %d\n", new_pos, cur_pos)); if (new_pos < cur_pos) RowUp(cur_pos-new_pos); if (new_pos > cur_pos) RowDown(new_pos-cur_pos); cur_pos = new_pos; si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = m_ScrollPos = cur_pos; CWnd::SetScrollInfo(SB_VERT,&si); } CWnd::OnVScroll(nSBCode, nPos, pScrollBar); } ///////////////////////////////////////////////////////////////////////////// // internal functions // these functions move the list pointer (m_ListItem) up or down a few rows. bool CGrListBox::RowUp(int rows, bool draw) { int old=m_ListItem; int done=0,count=0; bool retval=false; while ((count<(items_per_row*rows)) && !done) { int olditem; if (m_ListItem == m_ItemSel) retval = true; olditem = m_ListItem; m_ListItem = ListPrevItem(m_ListItem); //mprintf((0, "m_ListItem = %d\n", m_ListItem)); if (m_ListItem > olditem) { m_ListItem = olditem; done = 1; // mprintf((0, "m_ListItem = %d\n", m_ListItem)); } else if (old<=m_ListItem) { m_ListItem=old; done=1; } else count++; } if (draw) CWnd::Invalidate(); return retval; } bool CGrListBox::RowDown(int rows, bool draw) { int old=m_ListItem; int done=0,count=0; bool retval = false; while ((count<(items_per_row*rows)) && !done) { if (m_ListItem == m_ItemSel) retval = true; m_ListItem = ListNextItem(m_ListItem); if (old>=m_ListItem) { m_ListItem=old; done=1; } else count++; } if (draw) CWnd::Invalidate(); return retval; } int CGrListBox::CalcRowOfItem(int item) { int curitem = 0, oldcuritem=0; int column = 0; int row = 0; do { curitem = ListNextItem(curitem); column++; if (column == items_per_row) { row++; column = 0; } if (oldcuritem >= curitem) return 0; oldcuritem = curitem; } while (curitem != item); return row; } // draws all the items in the list, or don't draw. invoking DrawItem and uses the list management functions void CGrListBox::ListBoxProc(bool do_draw) { static bool in_listboxproc = false; grHardwareSurface m_ItemSurf; grHardwareSurface m_ItemSurfSel; RECT box_rect; int left, top, draw_x, draw_y; int box_width, box_height; int num_items, item; // don't draw if editor is in background. if (in_listboxproc) return; in_listboxproc = true; if (!Editor_active) do_draw = false; // initialize graphic objects CWnd::GetClientRect(&box_rect); box_height = box_rect.bottom - box_rect.top; box_width = box_rect.right - box_rect.left; if (do_draw) { Desktop_surf->attach_to_window((unsigned)CWnd::m_hWnd); Desktop_surf->clear(0,0,box_width,box_height); m_ItemSurf.create(m_SurfDimension,m_SurfDimension,BPP_16); m_ItemSurfSel.create(m_SurfDimension+8,m_SurfDimension+8,BPP_16); } // initialize list manager. items_per_row = box_width/(m_SurfDimension+8); items_max_row = box_height/(m_SurfDimension+8); m_ListLen = this->ListEnumerate(); m_ListItem = (m_ListItem/items_per_row)*items_per_row; // align rows correctly m_ListItem = this->ListFirstItem(m_ListItem); // start drawing items in list box. left = (box_width/2) - (items_per_row*(m_SurfDimension+8))/2; top = (box_height/2) - (items_max_row*(m_SurfDimension+8))/2; num_items = 0; item = m_ListItem; m_IsItemSelInBox = false; // this will turn true during the drawing loop // drawing and item selection check all purpose loop // if our start list function returned a -1, this means that there are no list items to draw! // also stop if we've exceeded the number of items that can exist in the limited box of visible // space. while ((m_ListItem > -1) && (num_items < (items_per_row * items_max_row))) { int previtem; // draw at draw_x, draw_y. go to next item in list and check if we are at end of list. draw_x = left + ((num_items % items_per_row) * (m_SurfDimension+8)); draw_y = top + ((num_items / items_per_row) * (m_SurfDimension+8)); previtem = item; if (m_CheckHit) if ( m_HitX>=draw_x && m_HitX<=(draw_x+m_SurfDimension+8) && m_HitY>=draw_y && m_HitY<=(draw_y+m_SurfDimension+8)) { m_ItemSel = item; OnItemSelected(m_ItemSel); m_CheckHit = false; } if (m_ItemSel == item) m_IsItemSelInBox = true; if (do_draw) { if (m_ItemSel == item) { if (m_SelectionBox) { grViewport vp(&m_ItemSurfSel); vp.clear(); vp.lock(); vp.rect(GR_RGB(255,0,255), 0,0,vp.width()-1,vp.height()-1); vp.rect(GR_RGB(255,0,255), 1,1,vp.width()-2,vp.height()-2); vp.rect(GR_RGB(255,0,255), 2,2,vp.width()-3,vp.height()-3); vp.unlock(); Desktop_surf->blt(draw_x-4,draw_y-4,vp.get_parent()); this->DrawItem(draw_x, draw_y, &m_ItemSurf, item); } else { this->DrawItem(draw_x-4, draw_y-4, &m_ItemSurfSel, item); } } else this->DrawItem(draw_x, draw_y, &m_ItemSurf, item); } item = this->ListNextItem(item); // break if we hit end of list. if (item <= previtem) break; num_items++; } // update the scroll bar // free up any graphic resources initialized here. if (do_draw) { SCROLLINFO si; si.cbSize = sizeof(si); si.fMask = SIF_ALL; si.nMin = 0; si.nMax = (m_ListLen / items_per_row) + ((m_ListLen % items_per_row) ? 0: -1); si.nPos = m_ScrollPos = CalcRowOfItem(m_ListItem); si.nPage = (si.nMax >= items_max_row) ? items_max_row : (si.nMax+1); CWnd::SetScrollInfo(SB_VERT, &si); CWnd::ShowScrollBar(SB_VERT); m_ItemSurfSel.free(); m_ItemSurf.free(); Desktop_surf->attach_to_window(NULL); } in_listboxproc = false; }