⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 listbox.c

📁 dos 1.0 其中包含quick basic源代码、内存管理himem emm386 发展历史
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
	COW : Character Oriented Windows
	(COW USER DIALOG)

	listbox.c : list boxes

    Note : much of the math in the module is excessive (i.e. WORDs for BYTES)
    Note : all far pointer control is performed with limited-lifetime pointers
*/


#define COW
#include <cow.h>

#include <udialog.h>
#include <uscroll.h>
#include <uwindow.h>
#include <uscreen.h>
#include <uisa.h>
#include <uevent.h>
#include <vkey.h>
#include <kinput.h>
#include <kkeyboar.h>
#include <kmem.h>		/* kernel exports for memory management */

/* really integrated into SDM */
#include <sdmver.h>
#include <usdm.h>
#include <usdmtmpl.h>
#include "sdm.h"

#include "window.h"
#include "dialog.h"
#include "event.h"
#include "scroll.h"
#include "screen.h"
#include "util.h"
#include "case.h"

#include "listbox.h"
#include "_listbox.h"

#ifdef LISTBOX_LIMIT_SIZE
#define	cchListTextMax	64
#else
#define	cchListTextMax	256
#endif


#ifdef EXTRAS
#ifndef LISTBOX_HORIZ
#define LISTBOX_COLOR			/* listbox content may contain color */
#endif
#endif

/* REVIEW: move this to WINDOW.H !!! */
#ifdef EXTRAS
#define	chColorPrefix	((char) 0xfe)		/* => special color prefix */
#endif

/* forward */

STATIC VOID DisplayListBox(PWND);
STATIC VOID FillListBox(PWND, RY, RY, WORD);
STATIC VOID ScrollListBox(PWND, short, BOOL);
STATIC VOID ScrollHorizListBox(PWND, short);	/* LISTBOX_HORIZ only */
STATIC VOID HiliteListSel(PWND, BOOL);
STATIC VOID MoveSelection(PWND, WORD);
STATIC VOID MoveSelectionDown(PWND);
STATIC VOID MoveSelectionUp(PWND);
STATIC VOID MoveSelectionLeft(PWND, WORD);	/* LISTBOX_HORIZ only */
STATIC VOID MoveSelectionRight(PWND, WORD);	/* LISTBOX_HORIZ only */
STATIC VOID SetScrollWindow(PWND);
STATIC VOID ResetContent(PWND);
STATIC VOID AddListSz(PWND, char *, WORD);
STATIC VOID InsertSz(PWND, WORD, char *, BOOL, WORD);
STATIC VOID ReplaceSz(PWND, WORD, char *);
STATIC VOID DeleteSz(PWND, WORD, WORD);
STATIC VOID RevertToOomLb(PWND, WORD);
STATIC BOOL FLocateMatch(PWND, WORD);
STATIC VOID GetOnDemand(PWND, WORD, WORD FAR **, char FAR **, char *);
STATIC VOID FAR * LpvDeref(WORD);
#ifdef KANJI
STATIC int fdircmp(char FAR *, char FAR *);
STATIC int fjstrcmp(unsigned char FAR *, unsigned char FAR *);
#endif



PUBLIC DWORD FARPUBLIC			/* WndProcs are PUBLIC */
ListBoxWndProc(pwnd, message, wParam, lParam)
/*
  -- WndProc for List Boxes
  -- handles all messages from SDM and Dialog manager
*/
REG PWND pwnd;
WORD	message;
WORD	wParam;
DWORD	lParam;
	{
	WORD	wSelect;	/* indicates cause of selection */
	WORD	iszNew;
	REG WORD iszCur;
	MSP	msp;
	RRC	rrc;
	short	dryLb;			/* height of listbox */

#ifdef LISTBOX_HORIZ
	BOOL	fHoriz = pwnd->style & WS_HSCROLL;
#endif /*LISTBOX_HORIZ*/

	Assert(pwnd->iszCurLb != iszNil);

#ifndef LISTBOX_HORIZ
	Assert(pwnd->axCursor == AxOfRx(pwnd, rxListBoxMin));
#endif
	GetClientRrc(pwnd,&rrc);
	iszCur = FSelected(pwnd) ? pwnd->iszCurLb : iszNil;
	dryLb = rrc.ryBottom;
	wSelect = 0;

	switch(message)
		{
	default:
	/*case WM_ACTIVATE:*/
ReturnFalse:
		return((DWORD) FALSE);
		break;

	case WM_PAINT:
#ifdef DEBUG
#ifndef LISTBOX_ONELINE
		AssertSz(rrc.ryBottom - rrc.ryTop >= 2,
			    "Listbox too small");
#endif /*LISTBOX_ONELINE*/
#endif /*DEBUG*/
		DrawBorder(pwnd, &boxSingle, pwnd->isaColor, NULL);
		DisplayListBox(pwnd);
		goto ReturnTrue;

	case WM_WANTFOCUS:
		return((DWORD) pwnd->cszLb);	/* returns FALSE if empty */
		/*break;*/

	case WM_SETFOCUS:
		Assert(pwnd->cszLb != 0);
		if (pwnd->pwndParent != NULL)
			SendMessage(pwnd->pwndParent, WM_DIALOG_SETFOCUS,
					pwnd->id, 0L);
		goto ReturnTrue;

	case WM_KILLFOCUS:
		if (pwnd->pwndParent != NULL)
			SendMessage(pwnd->pwndParent, WM_DIALOG_KILLFOCUS,
					pwnd->id, 0L);
		goto ReturnTrue;

	case LB_SETCURSEL:
		if (wParam == iszNil)
			{
			/* unselect it */
			HiliteListSel(pwnd, FALSE);
			SetFSelected(pwnd, FALSE);
			}
		else if (wParam < pwnd->cszLb && wParam != iszCur)
			{
			MoveSelection(pwnd, wParam);	/* move+draw */
			}
		else
			{
			/* invalid selection: if debugging give a warning */
			AssertSz(wParam < pwnd->cszLb, "Invalid listbox selection");
			goto ReturnFalse;	/* selection not set */
			}
	
		goto ReturnTrue;
		/*break;*/

	case WM_MOUSEMOVE:
		/* ignore non-capture & client moves */
		if (!FCaptured(pwnd) || (wParam & MK_NONCLIENT))
			goto ReturnTrue;
		/* else : fall through */

	case WM_LBUTTONDOWN:
	case WM_LBUTTONDBLCLK:
		msp.lParam = lParam;
		/* listbox must be non-empty & left button down */
		if (pwnd->cszLb == 0 || !(wParam & MK_LBUTTON))
			goto ReturnFalse;

		wSelect |= lbrMouse;

		/* we should have the mouse captured */
		if (!FCaptured(pwnd))
			{
			SetCapture(pwnd);
			SetAlarm(pwnd, ctickRepScrollStart);
			}

		if (!(wParam & MK_NONCLIENT))
			{
			/* in middle of listbox */
			SetFocus(pwnd);
			iszNew = pwnd->iszTopLb + msp.s.ry;
#ifdef LISTBOX_HORIZ
			if (fHoriz)
				{
				// bump extra width
				/* which column are we in ? */
				iszNew += ((msp.s.rx - rxListBoxMin) /
				    (pwnd->drxItemLb + 1)) * dryLb;
				}
#endif /*LISTBOX_HORIZ*/
			if (iszNew >= pwnd->cszLb)
				{
				wSelect = lbrOther;
				if (FSelected(pwnd))
					wSelect |= flbrReselect;
				iszCur = iszNil;    /* force message */
				}

			else if (message == WM_LBUTTONDBLCLK &&
			    iszNew == iszCur)
				{
				/* double click selection */
				if (FCaptured(pwnd))
					{
					ReleaseCapture();
					KillAlarm();
					}
				SendMessage(pwnd->pwndParent, WM_DIALOG,
				    pwnd->id, MAKELONG(0, LBN_DBLCLK));
				goto ReturnTrue;
				}
			else
				{
				if (iszNew == iszCur)
					wSelect |= flbrReselect;
				iszCur = iszNil;    /* force message */
				MoveSelection(pwnd, iszNew);
				}
			}
		else if (msp.s.ay < pwnd->arcClipping.ayTop)
			MoveSelectionUp(pwnd);
		else if (msp.s.ay >= pwnd->arcClipping.ayBottom)
			MoveSelectionDown(pwnd);
#ifdef LISTBOX_HORIZ
		/* special horizontal scroll */
		else if (msp.s.ax < pwnd->arcClipping.axLeft)
			MoveSelectionLeft(pwnd, 1);
		else if (msp.s.ax >= pwnd->arcClipping.axRight)
			MoveSelectionRight(pwnd, 1);
#endif /*LISTBOX_HORIZ*/
		break;

	case WM_ALARM:
		if (FCaptured(pwnd))
			{
			wSelect |= lbrMouse;
			SetAlarm(pwnd, pwnd->ctickRepLb);
			if (ayMouse < pwnd->arcClipping.ayTop)
				{
				MoveSelectionUp(pwnd);
				/* fast repeat ? */
				if (ayMouse < pwnd->arcClipping.ayTop - 2)
					SetAlarm(pwnd, pwnd->ctickRepLb / 2);
				}
			else if (ayMouse >= pwnd->arcClipping.ayBottom)
				{
				MoveSelectionDown(pwnd);
				/* fast repeat ? */
				if (ayMouse >= pwnd->arcClipping.ayBottom + 2)
					SetAlarm(pwnd, pwnd->ctickRepLb / 2);
				}
#ifdef LISTBOX_HORIZ
			/* special horizontal scroll (1 speed) */
			else if (axMouse < pwnd->arcClipping.axLeft)
				MoveSelectionLeft(pwnd, 1);
			else if (axMouse >= pwnd->arcClipping.axRight)
				MoveSelectionRight(pwnd, 1);
#endif /*LISTBOX_HORIZ*/
			}
		break;

	case WM_LBUTTONUP:
		if (!FCaptured(pwnd))
			goto ReturnFalse;	/* ignore */
		ReleaseCapture();
		KillAlarm();
		SendMessage(pwnd->pwndParent, WM_DIALOG, pwnd->id,
			MAKELONG(0,LBN_SELECT_DONE));
		goto ReturnTrue;
		/* break; */

	case WM_VSCROLL:
		{
		short	dry = 0;

		if (pwnd->cszLb == 0)
			goto ReturnFalse; /* nothing for empty listboxes */

		wSelect |= lbrScroll;

		switch (wParam)
			{
		default:
			break;

		case SB_LINEDOWN:
			dry++;			/* 1 line down */
			Assert(dry == 1);
			break;

		case SB_LINEUP:
			dry--;			/* 1 line up */
			Assert(dry == -1);
			break;

		case SB_PAGEDOWN:
			dry = dryLb;
			break;

		case SB_PAGEUP:
			dry = -dryLb;
			break;

		case SB_THUMBPOSITION:
			dry = LOWORD(lParam) - pwnd->iszTopLb;
			break;

		case SB_UPCLICK:
			SendMessage(pwnd->pwndParent, WM_DIALOG, pwnd->id,
				MAKELONG(0,LBN_SELECT_DONE));
			break;

			}

		if (dry != 0)
			ScrollListBox(pwnd, dry, TRUE);
		}
		break;

#ifdef LISTBOX_HORIZ

	case WM_HSCROLL:
		{
		if (pwnd->cszLb == 0)
			goto ReturnFalse; /* nothing for empty listboxes */

		wSelect |= lbrScroll;

		/* move selection (since scrolling makes no sense */
		switch (wParam)
			{
		default:
			break;

		case SB_LINEDOWN:
			MoveSelectionRight(pwnd, 1);
			break;

		case SB_LINEUP:
			MoveSelectionLeft(pwnd, 1);
			break;

		case SB_PAGEDOWN:
			MoveSelectionRight(pwnd, pwnd->citemWidthLb);
			break;

		case SB_PAGEUP:
			MoveSelectionLeft(pwnd, pwnd->citemWidthLb);
			break;

		case SB_THUMBPOSITION:
			{
			WORD	iszNew;
			iszNew = LOWORD(lParam) * dryLb + iszCur % dryLb;

			if (iszNew >= pwnd->cszLb)
				iszNew = pwnd->cszLb - 1;
			MoveSelection(pwnd, iszNew);
			}
			break;

			}/*switch*/

		}
		break;
#endif /*LISTBOX_HORIZ*/

	case LB_RESETCONTENT:
		ResetContent(pwnd);
		goto ReturnTrue;
		/*break;*/

	case LB_ADDSTRING:
		AddListSz(pwnd, (char *) wParam, LOWORD(lParam));
		goto ReturnTrue;
		/*break;*/

	case LB_INSERTSTRING:
		InsertSz(pwnd, HIWORD(lParam), (char *) wParam, FALSE, LOWORD(lParam));
		goto ReturnTrue;
		/*break;*/

	case LB_REPLACESTRING:
		ReplaceSz(pwnd, HIWORD(lParam), (char *) wParam);
		goto ReturnTrue;
		/*break;*/

	case LB_DELETESTRING:
		DeleteSz(pwnd, HIWORD(lParam), LOWORD(lParam));
		goto ReturnTrue;
		/*break;*/

	case LB_GETCURSEL:
		return ((DWORD) iszCur);
		/*break;*/

	case LB_GETCOUNT:
		return ((DWORD) pwnd->cszLb);
		/*break;*/

	case LB_GETTEXT:
		return ((DWORD) GetListText(
			pwnd, (char *) wParam, HIWORD(lParam)));
		/*break;*/

#ifdef LISTBOX_HORIZ
	case LB_SETWIDTH:
		/* set # item width for horizontal listboxes
		   (wParam == citem) -- usually sent before repainting */
		Assert(wParam != 0);

		pwnd->citemWidthLb = wParam;
		/* 1 extra at start and after each row */
		Assert(rxListBoxMin == 1);
		pwnd->drxItemLb = ((rrc.rxRight - 1) / wParam) - 1;

		/* KLUDGE: convert vertical listbox into horizontal */
		if (pwnd->style & WS_VSCROLL)
			{
			REG PWND pwndScrl;

			pwndScrl = PwndChild(pwnd);
			Assert(pwndScrl != NULL);
			Assert(pwndScrl->style & SBS_VERT);

			// switch scroll bar position (to bottom)
			pwndScrl->arcWindow.axLeft = pwnd->arcWindow.axLeft +
			    daxBorder;
			pwndScrl->arcWindow.axRight = pwnd->arcWindow.axRight -
			    daxBorder;
			pwndScrl->arcWindow.ayTop =
			   (pwndScrl->arcWindow.ayBottom =
			    pwnd->arcWindow.ayBottom) - dayBorder;

			// switch style & validate
			pwndScrl->style = (pwndScrl->style & ~SBS_VERT) | SBS_HORZ;
			ValidateWindow(pwndScrl);

			// switch parent style
			pwnd->style = (pwnd->style & ~WS_VSCROLL) | WS_HSCROLL;
			ValidateWindow(pwnd);
			}
		goto ReturnTrue;
#endif /*LISTBOX_HORIZ*/

	case WM_CHAR:
		/* return FALSE if key ignored */
		if ((HIWORD(lParam) & KK_MENU) || (!pwnd->fEnabled))
			goto ReturnFalse;	/* pass ALT keys through */

		UndoRepeat(wParam, lParam);

		wSelect |= lbrKeys;

		switch(wParam)
			{
		default:
			/* we should eat all non-control ascii keys
			* (they may or may not do anything)
			* control keys and non-ascii will not be eaten
			*/
			if (!FLocateMatch(pwnd, wParam) &&
			   (wParam < 0x20 || wParam >= VK_MIN))
				{
				/* control or non-ascii did not match */
				goto ReturnFalse;
				}
			break;

		case VK_LEFT:
#ifdef LISTBOX_HORIZ
			MoveSelectionLeft(pwnd, 1);
			break;
#endif /*LISTBOX_HORIZ*/

		case VK_UP:
			MoveSelectionUp(pwnd);
			break;

		case VK_RIGHT:
#ifdef LISTBOX_HORIZ
			MoveSelectionRight(pwnd, 1);
			break;
#endif /*LISTBOX_HORIZ*/

		case VK_DOWN:
			MoveSelectionDown(pwnd);
			break;

		case VK_NEXT:
#ifdef LISTBOX_HORIZ
			if (fHoriz)
				MoveSelectionRight(pwnd, pwnd->citemWidthLb);
			else
#endif /*LISTBOX_HORIZ*/
				ScrollListBox(pwnd, dryLb, TRUE);
			break;

		case VK_PRIOR:
#ifdef LISTBOX_HORIZ
			if (fHoriz)
				MoveSelectionLeft(pwnd, pwnd->citemWidthLb);
			else
#endif /*LISTBOX_HORIZ*/
				ScrollListBox(pwnd, -dryLb, TRUE);
			break;

		case ' ':
			wSelect = flbrReselect | lbrSpace;
			/* force message for change of selection */
			iszCur = iszNil;	/* force a change */
			HiliteListSel(pwnd, TRUE);
			break;

		case VK_HOME:
			if (pwnd->cszLb != 0)
				MoveSelection(pwnd, iszMin);
			break;

		case VK_END:
			if (pwnd->cszLb != 0)
				MoveSelection(pwnd, pwnd->cszLb - 1);
			break;

			}
		break;
		}

	if (FSelected(pwnd) && iszCur != pwnd->iszCurLb)
		{
		/* tell parent that selection has changed */
		Assert((wSelect & lbrCause) != lbrNone)
		SendMessage(pwnd->pwndParent, WM_DIALOG, pwnd->id,
		    MAKELONG(wSelect, LBN_SELCHANGE));
		}

ReturnTrue:
	return((DWORD) TRUE);	/* default case */
	}



STATIC VOID
DisplayListBox(pwnd)
/*
  -- display the contents of the list box
*/
REG PWND pwnd;
	{
	RRC	rrc;

	Assert(fDrawItem);

	GetClientRrc(pwnd, &rrc);
	FillRrc(pwnd, &rrc, ' ', pwnd->isaColor);

	if (pwnd->cszLb > 0)
		FillListBox(pwnd, 0, rrc.ryBottom, pwnd->iszTopLb);

	SetScrollWindow(pwnd);
	}



STATIC VOID
SetScrollWindow(pwnd)
/*
  -- sets the scroll range and position
  -- vertical is simple, horizontal is a pain
*/
REG PWND pwnd;
	{
	RRC	rrc;
	/* check for no scrollbar */
#ifdef LISTBOX_ONELINE
	if (!(pwnd->style & (WS_VSCROLL | WS_HSCROLL)))
		return;
#else
	Assert(pwnd->style & (WS_VSCROLL | WS_HSCROLL));
#endif /*LISTBOX_ONELINE*/

	GetClientRrc(pwnd,&rrc);
#ifdef LISTBOX_HORIZ
	if (pwnd->style & WS_HSCROLL)
		{
		REG short colMac;
		BYTE	dry;

		dry = rrc.ryBottom;
		colMac = (pwnd->cszLb - 1) / dry + 1;

		SetScrollRange(pwnd->pwndChild, 0, colMac, FALSE);
		SetScrollPos(pwnd->pwndChild, pwnd->iszCurLb / dry, TRUE);
		}
	else
#endif	/*LISTBOX_HORIZ*/
		{
		// vertical listbox case
		REG short iszBot;

		iszBot = pwnd->cszLb - rrc.ryBottom;
		if (iszBot < 1)
			iszBot = 1;	/* set range to 1 */

		SetScrollRange(pwnd->pwndChild, 0, iszBot, FALSE);
		SetScrollPos(pwnd->pwndChild, pwnd->iszTopLb, TRUE);
		}
	}



STATIC VOID
FillListBox(pwnd, ryTop, ryBottom, isz)
/*
  -- fill in the specified lines in the listbox
  -- ryTop is the top line, ryBottom is the bottom line
  -- isz is the isz corresponding to the top line
*/
REG PWND pwnd;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -