home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1996-10-16 | 24.4 KB | 890 lines | [ TEXT/CWIE]
unit MyTextDisplay; interface uses Windows; type LongArray = array[1..100000] of longint; LongArrayPtr = ^LongArray; LongArrayHandle = ^LongArrayPtr; MyTextDisplayRecord = record { You can change these and the call resize/recalc } leading: integer; width: integer; leave_room_for_grow: boolean; { You can read these } full_rect: Rect; view: Rect; full_view: Rect; view_lines: longint; total_length: longint; view_width: integer; top_line: longint; selStart, selEnd: longint; hoffset: integer; window: WindowPtr; hcontrol, vcontrol: ControlHandle; font: integer; size: integer; fi: FontInfo; line_height: longint; rn: integer; lines: longint; { You should ignore these } last_click_time: longint; last_click_offset: longint; double_click: boolean; offsets: LongArrayHandle; end; LongPoint = record v: longint; h: longint; end; procedure MTDCreate (var mtd: MyTextDisplayRecord; window: WindowPtr; rn: integer; width: integer; hcontrol: boolean); procedure MTDDestroy (var mtd: MyTextDisplayRecord); procedure MTDSetPort (var mtd: MyTextDisplayRecord); procedure MTDSetFontSize (var mtd: MyTextDisplayRecord; font, size: integer); procedure MTDRecalculate (var mtd: MyTextDisplayRecord; justappend: boolean); procedure MTDDisplay (var mtd: MyTextDisplayRecord; draw_region: RgnHandle; fromline: longint); procedure MTDSetSelection (var mtd: MyTextDisplayRecord; start, fin: longint); procedure MTDGetSelectionData (var mtd: MyTextDisplayRecord; h: Handle); procedure MTDResize (var mtd: MyTextDisplayRecord; view: Rect); procedure MTDDoKey (var mtd: MyTextDisplayRecord; ch: char); procedure MTDDoClick (var mtd: MyTextDisplayRecord; const er: EventRecord); procedure MTDSetMouse (var mtd: MyTextDisplayRecord); procedure MTDScroll (var mtd: MyTextDisplayRecord; scroll: LongPoint); procedure MTDActivateDeactivate (var mtd: MyTextDisplayRecord; activate: boolean); implementation uses TextUtils, ToolUtils, Devices, Types, ICAPI, MyTypes, MyInternetConfig, MyMathUtils, MyFileSystemUtils, MyCursors, MyUtils, MyEvents, MyMemory, MyAssertions; const invis = 0; vis = 255; procedure SectRectRgn (rgn: RgnHandle; r: Rect); var rrgn: RgnHandle; begin rrgn := NewRgn; RectRgn(rrgn, r); SectRgn(rgn, rrgn, rgn); DisposeRgn(rrgn); end; procedure UnionRectRgn (rgn: RgnHandle; l, t, r, b: integer); var rrgn: RgnHandle; begin rrgn := NewRgn; SetRectRgn(rrgn, l, t, r, b); UnionRgn(rgn, rrgn, rgn); DisposeRgn(rrgn); end; function MyFSReadChunkPos (refnum: integer; pos: longint; var len: longint; datap:Ptr): OSErr; var pb: ParamBlockRec; err: OSErr; begin pb.ioRefNum := refnum; pb.ioBuffer := datap; pb.ioReqCount := len; pb.ioPosMode := fsFromStart; pb.ioPosOffset := pos; err := PBReadSync(@pb); if (err = eofErr) & (pb.ioActCount > 0) then begin err := noErr; end; len := Choose( err = noErr, pb.ioActCount, 0 ); MyFSReadChunkPos := err; end; function MyFSReadChunkPosLine (refnum: integer; pos: longint; len: integer; var s: Str255): OSErr; var mylen: longint; err: OSErr; begin {$PUSH} {$R-} mylen := Min( len, 255 ); err := MyFSReadChunkPos( refnum, pos, mylen, @s[1] ); s[0] := chr(mylen); {$POP} MyFSReadChunkPosLine := err; end; procedure MTDSetPort (var mtd: MyTextDisplayRecord); begin SetPort(mtd.window); TextFont(mtd.font); TextSize(mtd.size); TextFace([]); end; procedure MTDOffsetToLine (var mtd: MyTextDisplayRecord; offset: longint; var thisline: longint); var s, m, f: longint; begin if offset <= 0 then begin thisline := 1; end else if offset >= mtd.total_length then begin thisline := mtd.lines; end else begin s := 1; f := mtd.lines + 1; while s < f do begin m := (f + s) div 2; if offset >= mtd.offsets^^[m] then begin s := m; end; if offset < mtd.offsets^^[m + 1] then begin f := m; end; if offset = mtd.offsets^^[m + 1] then begin { cheat to make it work with filelen } s := m + 1; leave; end; end; thisline := s; end; end; procedure MTDSetFontSize (var mtd: MyTextDisplayRecord; font, size: integer); begin mtd.font := font; mtd.size := size; if size = 0 then begin mtd.leading := 2; end else begin mtd.leading := size div 6; if mtd.leading = 0 then begin mtd.leading := 1; end; end; MTDSetPort(mtd); GetFontInfo(mtd.fi); mtd.line_height := mtd.fi.ascent + mtd.fi.descent + mtd.leading; end; procedure MTDSetControls (var mtd: MyTextDisplayRecord); var m: integer; begin mtd.vcontrol^^.contrlVis := invis; m := Max(0, mtd.lines - mtd.view_lines); SetControlMaximum(mtd.vcontrol, m); mtd.top_line := Pin(0, mtd.top_line, m); SetControlValue(mtd.vcontrol, mtd.top_line); mtd.vcontrol^^.contrlVis := vis; Draw1Control(mtd.vcontrol); if mtd.hcontrol <> nil then begin mtd.hcontrol^^.contrlVis := invis; m := Max(0, mtd.width - mtd.view_width); SetControlMaximum(mtd.hcontrol, m); mtd.hoffset := Pin(0, mtd.hoffset, m); SetControlValue(mtd.hcontrol, mtd.hoffset); mtd.hcontrol^^.contrlVis := vis; Draw1Control(mtd.hcontrol); end; end; procedure MTDRecalculate (var mtd: MyTextDisplayRecord; justappend: boolean); var err: OSErr; handlesize: longint; pos, nextpos: longint; offset, linebytes: longint; filelen: longint; line: Str255; slbc: StyledLineBreakCode; textwidth: Fixed; orgoffset: longint; thisline: longint; initialline: longint; begin MTDSetPort(mtd); mtd.last_click_time := 0; handlesize := GetHandleSize(Handle(mtd.offsets)) div 4; err := GetEOF(mtd.rn, filelen); mtd.total_length := filelen; if justappend & (mtd.lines > 1) then begin mtd.lines := mtd.lines - 1; pos := mtd.offsets^^[mtd.lines + 1]; orgoffset := maxLongInt; initialline := 0; {mtd.lines} end else begin orgoffset := mtd.offsets^^[Min(mtd.lines + 1, mtd.top_line + 1)]; mtd.lines := 0; pos := 0; initialline := 0; end; if err = noErr then begin err := MyFSReadLineAt(mtd.rn, pos, line); while err = noErr do begin nextpos := pos + length(line) + 1; offset := 0; while (offset = 0) or (offset < length(line)) do begin textwidth := BSL(mtd.width, 16); linebytes := 1; slbc := StyledLineBreak(@line[offset + 1], length(line) - offset, 0, length(line) - offset, 0, textwidth, linebytes); mtd.lines := mtd.lines + 1; if mtd.lines > handlesize then begin handlesize := handlesize + 100; SetHandleSize(Handle(mtd.offsets), handlesize * 4); end; mtd.offsets^^[mtd.lines] := pos + offset; if linebytes = 0 then begin offset := offset + 1; end else begin offset := offset + linebytes; end; end; pos := nextpos; err := MyFSReadLineAt(mtd.rn, pos, line); end; end; SetHandleSize(Handle(mtd.offsets), (mtd.lines + 1) * 4); mtd.offsets^^[mtd.lines + 1] := filelen; mtd.hoffset := 0; MTDOffsetToLine(mtd, orgoffset, thisline); mtd.top_line := Max(0, Min(thisline - 1, mtd.lines - mtd.view_lines)); MTDSetControls(mtd); MTDDisplay(mtd, nil, initialline); end; function MTDLinePosToHOffset (var mtd: MyTextDisplayRecord; var line: Str255; linepos: integer): integer; begin {$PUSH} {$R-} MTDLinePosToHOffset := Char2Pixel(@line[1], length(line), 0, linepos, 1) + mtd.view.left - mtd.hoffset; {$POP} end; function MTDHOffsetToLinePos (var mtd: MyTextDisplayRecord; var line: Str255; hoffset: integer; var rightside: boolean): integer; var linepos: integer; begin {$unused(mtd)} {$PUSH} {$R-} linepos := Pixel2Char(@line[1], length(line), 0, hoffset, rightside); {$POP} rightside := rightside <> false; MTDHOffsetToLinePos := linepos; end; procedure MTDDisplay (var mtd: MyTextDisplayRecord; draw_region: RgnHandle; fromline: longint); var line: Str255; function LineSelectionPos (thisline, o: longint): integer; var base, pos: longint; begin base := mtd.offsets^^[thisline]; if o <= base then begin LineSelectionPos := mtd.view.left; end else if o >= mtd.offsets^^[thisline + 1] then begin LineSelectionPos := mtd.view.right; end else begin pos := MTDLinePosToHOffset(mtd, line, o - base); if pos < mtd.view.left then begin pos := mtd.full_view.left; end else if pos >= mtd.view.right then begin pos := mtd.full_view.right; end; LineSelectionPos := pos; end; end; var err: OSErr; v: integer; thisline: longint; s, f: longint; sh, fh: integer; oldclip: RgnHandle; r: Rect; begin MTDSetPort(mtd); oldclip := NewRgn; GetClip(oldclip); if draw_region = nil then begin ClipRect(mtd.view); end else begin SectRectRgn(draw_region, mtd.view); SetClip(draw_region); end; v := mtd.view.top + mtd.leading + mtd.fi.ascent; for thisline := mtd.top_line + 1 to Min(mtd.lines, mtd.top_line + mtd.view_lines) do begin if thisline >= fromline then begin err := MyFSReadChunkPosLine(mtd.rn, mtd.offsets^^[thisline], mtd.offsets^^[thisline + 1] - mtd.offsets^^[thisline], line); if err <> noErr then begin leave; end; r := mtd.view; r.top := v - mtd.fi.ascent - mtd.leading; r.bottom := v + mtd.fi.descent; MoveTo(mtd.view.left - mtd.hoffset, v); EraseRect(r); DrawString(line); s := mtd.selStart; f := mtd.selEnd; if (s < f) & (s < mtd.offsets^^[thisline + 1]) & (mtd.offsets^^[thisline] < f) then begin { Selection } sh := LineSelectionPos(thisline, s); fh := LineSelectionPos(thisline, f); SetRect(r, sh, v - mtd.fi.ascent - mtd.leading, fh, v + mtd.fi.descent); HiliteInvertRect(r); end; end; v := v + mtd.line_height; end; SetClip(oldclip); DisposeRgn(oldclip); end; procedure MTDScroll (var mtd: MyTextDisplayRecord; scroll: LongPoint); var update: RgnHandle; begin scroll.v := Pin(-mtd.top_line, scroll.v, Max(0, mtd.lines - mtd.top_line - mtd.view_lines)); scroll.h := Pin(-mtd.hoffset, scroll.h, Max(0, mtd.width - mtd.hoffset - mtd.view_width)); if (scroll.v <> 0) or (scroll.h <> 0) then begin update := NewRgn; ScrollRect(mtd.view, -scroll.h, -scroll.v * mtd.line_height, update); mtd.hoffset := mtd.hoffset + scroll.h; mtd.top_line := mtd.top_line + scroll.v; MTDDisplay(mtd, update, 0); DisposeRgn(update); MTDSetControls(mtd); end; end; procedure MTDPointToOffset (var mtd: MyTextDisplayRecord; pt: Point; var thisline, offset: longint; var rightside: boolean; var line: Str255; var scroll: LongPoint); var last_line: longint; h: integer; err: OSErr; begin rightside := false; scroll.h := 0; scroll.v := 0; line := ''; last_line := Min(mtd.top_line + mtd.view_lines, mtd.lines); if pt.v < mtd.full_view.top then begin scroll.v := -((mtd.view.top - pt.v) div mtd.line_height + 1); offset := mtd.offsets^^[mtd.top_line + 1]; thisline := mtd.top_line + 1; end else if pt.v > mtd.full_view.bottom then begin scroll.v := (pt.v - mtd.view.bottom) div mtd.line_height + 1; offset := mtd.offsets^^[last_line + 1]; thisline := last_line; rightside := false; end else begin if pt.h < mtd.full_view.left then begin scroll.h := pt.h - mtd.view.left; end else if pt.h > mtd.full_view.right then begin scroll.h := pt.h - mtd.view.right; end else begin pt.h := Pin(mtd.view.left, pt.h, mtd.view.right); end; thisline := mtd.top_line + (pt.v - mtd.view.top) div mtd.line_height + 1; if thisline > mtd.lines then begin thisline := mtd.lines + 1; offset := mtd.total_length; rightside := false; end else begin h := Max(0, pt.h - mtd.view.left + mtd.hoffset); err := MyFSReadChunkPosLine(mtd.rn, mtd.offsets^^[thisline], mtd.offsets^^[thisline + 1] - mtd.offsets^^[thisline], line); offset := MTDHOffsetToLinePos(mtd, line, h, rightside); if offset >= length(line) then begin offset := length(line); rightside := false; end; offset := mtd.offsets^^[thisline] + offset; end; end; end; procedure MTDReadLine (var mtd: MyTextDisplayRecord; theline: longint; var line: Str255); var err: OSErr; begin line := ''; if theline <= mtd.lines then begin err := MyFSReadChunkPosLine(mtd.rn, mtd.offsets^^[theline], mtd.offsets^^[theline + 1], line); end; end; procedure MTDOffsetToPoint (var mtd: MyTextDisplayRecord; offset: longint; var pt: Point); var thisline: longint; line: Str255; begin MTDOffsetToLine(mtd, offset, thisline); if thisline <= mtd.top_line then begin pt := mtd.view.topLeft; pt.v := pt.v - mtd.line_height; end else if thisline >= mtd.top_line + mtd.view_lines + 1 then begin pt := mtd.view.botRight; pt.v := pt.v + mtd.line_height; end else begin MTDReadLine(mtd, thisline, line); pt.v := mtd.view.top + mtd.leading + mtd.fi.ascent + (thisline - mtd.top_line - 1) * mtd.line_height; pt.h := MTDLinePosToHOffset(mtd, line, offset - mtd.offsets^^[thisline]); end; end; procedure MTDGetSelectionData (var mtd: MyTextDisplayRecord; h: Handle); var err: OSErr; begin HUnlock(h); SetHandleSize(h, 0); SetHandleSize(h, mtd.selEnd - mtd.selStart); err := MyFSReadAt(mtd.rn, mtd.selStart, GetHandleSize(h), h^); if err <> noErr then begin SetHandleSize(h, 0); end; end; procedure MTDSetSelection (var mtd: MyTextDisplayRecord; start, fin: longint); function InView (v: integer): boolean; begin InView := (mtd.view.top <= v) & (v <= mtd.view.bottom); end; procedure GetSelRgn (s, f: longint; r: RgnHandle); var sp, fp: Point; ascent, descent, leading, left, right, top, bottom: integer; t, b: integer; begin if s < f then begin MTDOffsetToPoint(mtd, s, sp); MTDOffsetToPoint(mtd, f, fp); ascent := mtd.fi.ascent + mtd.leading; descent := mtd.fi.descent; leading := mtd.fi.leading; left := mtd.view.left; right := mtd.view.right; top := mtd.view.top; bottom := mtd.view.bottom; if sp.v = fp.v then begin if InView(sp.v) then begin SetRectRgn(r, sp.h, sp.v - ascent - leading, fp.h, sp.v + descent); end; end else begin if InView(sp.v) then begin SetRectRgn(r, sp.h, sp.v - ascent - leading, right, sp.v + descent); t := sp.v + descent; end else begin t := top; end; if InView(fp.v) then begin UnionRectRgn(r, left, fp.v - ascent - leading, fp.h, fp.v + descent); b := fp.v - ascent; end else begin b := bottom; end; UnionRectRgn(r, left, t, right, b); end; end; SectRectRgn(r, mtd.full_view); end; var orgn, nrgn: RgnHandle; begin if (start <> mtd.selStart) or (fin <> mtd.selEnd) then begin MTDSetPort(mtd); orgn := NewRgn; nrgn := NewRgn; GetSelRgn(mtd.selStart, mtd.selEnd, orgn); mtd.selStart := start; mtd.selEnd := fin; GetSelRgn(mtd.selStart, mtd.selEnd, nrgn); XorRgn(orgn, nrgn, nrgn); HiliteInvertRgn(nrgn); DisposeRgn(nrgn); DisposeRgn(orgn); end; end; procedure MTDResize (var mtd: MyTextDisplayRecord; view: Rect); var inset: integer; begin mtd.vcontrol^^.contrlVis := invis; if mtd.hcontrol <> nil then begin mtd.hcontrol^^.contrlVis := invis; end; EraseRect(mtd.full_rect); InvalRect(mtd.full_rect); mtd.full_rect := view; mtd.view := view; mtd.view.right := view.right - 16; if (mtd.hcontrol <> nil) then begin mtd.view.bottom := mtd.view.bottom - 16; end; mtd.full_view := mtd.view; inset := Max(mtd.leading, 3); InsetRect(mtd.view, inset, inset); mtd.view_lines := (mtd.view.bottom - mtd.view.top) div mtd.line_height; mtd.view.bottom := mtd.view.top + mtd.view_lines * mtd.line_height; mtd.view_width := mtd.view.right - mtd.view.left; if mtd.width = 0 then begin mtd.width := mtd.view_width; end; MoveControl(mtd.vcontrol, view.right - 15, view.top - 1); SizeControl(mtd.vcontrol, 16, view.bottom - view.top - 16 * ord(mtd.leave_room_for_grow) + 3); if mtd.hcontrol <> nil then begin MoveControl(mtd.hcontrol, view.left - 1, view.bottom - 15); SizeControl(mtd.hcontrol, view.right - view.left - 13, 16); end; MTDRecalculate(mtd, false); end; procedure MTDCreate (var mtd: MyTextDisplayRecord; window: WindowPtr; rn: integer; width: integer; hcontrol: boolean); var bounds: Rect; begin mtd.window := window; SetRect(mtd.view, 0, 0, 0, 0); mtd.width := width; mtd.leave_room_for_grow := true; mtd.rn := rn; mtd.lines := 0; mtd.total_length := 0; mtd.top_line := 0; mtd.hoffset := 0; mtd.selStart := 0; mtd.selEnd := 0; mtd.last_click_time := 0; mtd.offsets := LongArrayHandle(NewHandleClear(4)); SetRect(bounds, 0, 0, 15, 100); mtd.vcontrol := NewControl(window, bounds, '', false, 0, 0, 0, scrollBarProc, ord(@mtd)); if hcontrol then begin SetRect(bounds, 0, 0, 100, 15); mtd.hcontrol := NewControl(window, bounds, '', false, 0, 0, 0, scrollBarProc, ord(@mtd)); end else begin mtd.hcontrol := nil; end; MTDSetFontSize(mtd, 0, 0); end; var action_mte: ^MyTextDisplayRecord; action_amount: LongPoint; procedure MTDAction (control: ControlHandle; part: integer); begin {$unused(control)} if (part <> 0) then begin MTDScroll(action_mte^, action_amount); end; end; procedure GetActionAmount (var mtd: MyTextDisplayRecord; control: ControlHandle; part: integer; var scroll: LongPoint); var amount, amount_pg, amount_line: integer; begin if control = mtd.vcontrol then begin amount_pg := mtd.view_lines - 1; amount_line := 1; end else begin amount_pg := mtd.view_width; amount_line := 8; { a few pixels } end; case part of kControlUpButtonPart: amount := -amount_line; kControlDownButtonPart: amount := amount_line; kControlPageUpPart: amount := -amount_pg; kControlPageDownPart: amount := amount_pg; otherwise begin amount := 0; end; end; if control = mtd.vcontrol then begin scroll.h := 0; scroll.v := amount; end else begin scroll.h := amount; scroll.v := 0; end; end; procedure DoCommandClick(var mtd: MyTextDisplayRecord; offset: longint); var space: packed array[0..4095] of Byte; urlStart, urlEnd: longint; spaceStart, spaceEnd: longint; len: longint; err: OSStatus; f: longint; begin if (mtd.selStart < mtd.selEnd) & (mtd.selStart <= offset) & (offset <= mtd.selEnd) & (mtd.selStart + SizeOf(space) > mtd.selEnd) then begin { we have a smallish selection and we cmd-clicked in it } urlStart := mtd.selStart; urlEnd := mtd.selEnd; end else begin urlStart := offset; urlEnd := offset; end; spaceStart := Max( 0, urlStart - ((SizeOf(space) - (urlEnd - urlStart)) div 2) ); spaceEnd := Min( spaceStart + SizeOf(space), mtd.total_length ); len := spaceEnd - spaceStart; err := MyFSReadChunkPos( mtd.rn, spaceStart, len, @space ); if (err = noErr) & (len <> spaceEnd - spaceStart) then begin err := -1; end; if err = noErr then begin urlStart := urlStart - spaceStart; urlEnd := urlEnd - spaceStart; err := ICLaunchURL (internet_config_instance, '', @space, len, urlStart, urlEnd); urlStart := urlStart + spaceStart; urlEnd := urlEnd + spaceStart; end; if err = noErr then begin MTDSetSelection(mtd, urlStart, urlEnd); Delay( 6, f ); MTDSetSelection(mtd, urlStart, urlStart); Delay( 6, f ); MTDSetSelection(mtd, urlStart, urlEnd); end else begin SysBeep( 1 ); end; end; procedure MTDDoClick (var mtd: MyTextDisplayRecord; const er: EventRecord); var click_type: (CT_First, CT_Double, CT_Tripple); rightside: boolean; thisline: longint; line: Str255; procedure GetCurrentPos (offset: longint; var s, f: longint); var base: longint; offtab: OffsetTable; begin base := mtd.offsets^^[thisline]; case click_type of CT_First: begin s := offset + ord(rightside); f := offset + ord(rightside); end; CT_Double: begin {$PUSH} {$R-} FindWord(@line[1], length(line), offset - base, rightside, nil, offtab); {$POP} s := base + offtab[0].offFirst; f := base + offtab[0].offSecond; end; CT_Tripple: begin s := base; if thisline <= mtd.lines then begin f := mtd.offsets^^[thisline + 1]; end else begin f := base; end; end; end; { case } end; var pt: Point; control: ControlHandle; part: integer; scroll: LongPoint; offset, ancors, ancorf, s, f, value: longint; shift: boolean; amount: longint; MTDActionProc:UniversalProcPtr; begin MTDSetPort(mtd); pt := er.where; GlobalToLocal(pt); if PtInRect(pt, mtd.full_view) then begin shift := EventHasShiftKey( er ); MTDPointToOffset(mtd, pt, thisline, offset, rightside, line, scroll); if EventHasCommandKey( er ) then begin DoCommandClick( mtd, offset ); end else begin if not shift & (er.when - mtd.last_click_time <= GetDblTime) & (offset = mtd.last_click_offset) then begin if mtd.double_click then begin click_type := CT_Tripple; end else begin click_type := CT_Double; end; mtd.double_click := true; end else begin click_type := CT_First; mtd.double_click := false; mtd.last_click_offset := offset; end; if not shift then begin GetCurrentPos(offset, ancors, ancorf); end else begin if mtd.selStart < mtd.selEnd then begin if offset > mtd.selStart then begin ancors := mtd.selStart; ancorf := mtd.selStart; end else begin ancors := mtd.selEnd; ancorf := mtd.selEnd; end; end else begin ancors := offset; ancorf := offset; end; end; MTDSetSelection(mtd, ancors, ancorf); while StillDown do begin GetMouse(pt); MTDPointToOffset(mtd, pt, thisline, offset, rightside, line, scroll); GetCurrentPos(offset, s, f); MTDSetSelection(mtd, Min(ancors, s), Max(ancorf, f)); MTDScroll(mtd, scroll); end; mtd.last_click_time := TickCount; end; end else begin part := FindControl(pt, mtd.window, control); if part <> 0 then begin if part = kControlIndicatorPart then begin value := GetControlValue(control); part := TrackControl(control, pt, nil); if part <> 0 then begin amount := GetControlValue(control) - value; if amount <> 0 then begin if control = mtd.vcontrol then begin scroll.v := amount; scroll.h := 0; end else begin scroll.h := amount; scroll.v := 0; end; MTDScroll(mtd, scroll); end; end; end else begin GetActionAmount(mtd, control, part, action_amount); action_mte := @mtd; MTDActionProc := NewControlActionProc(MTDAction); value := TrackControl(control, pt, MTDActionProc); DisposeRoutineDescriptor(MTDActionProc); end; end else begin SysBeep(1); end; end; end; procedure MTDDoKey (var mtd: MyTextDisplayRecord; ch: char); var scroll: LongPoint; begin scroll.h := 0; scroll.v := 0; case ord(ch) of homeChar: begin scroll.v := -mtd.lines; end; endChar: begin scroll.v := mtd.lines; end; pageUpChar: begin GetActionAmount(mtd, mtd.vcontrol, kControlPageUpPart, scroll); end; pageDownChar: begin GetActionAmount(mtd, mtd.vcontrol, kControlPageDownPart, scroll); end; otherwise begin SysBeep(1); end; end; MTDScroll(mtd, scroll); end; procedure MTDSetMouse (var mtd: MyTextDisplayRecord); var pt: Point; begin SetPort(mtd.window); GetMouse(pt); if PtInRect(pt, mtd.full_view) then begin CursorSetIBeam; end else begin CursorSetArrow; end; end; procedure MTDActivateDeactivate (var mtd: MyTextDisplayRecord; activate: boolean); begin if activate then begin ShowControl(mtd.vcontrol); if mtd.hcontrol <> nil then begin ShowControl(mtd.hcontrol); end; end else begin HideControl(mtd.vcontrol); if mtd.hcontrol <> nil then begin HideControl(mtd.hcontrol); end; end; end; procedure MTDDestroy (var mtd: MyTextDisplayRecord); begin MDisposeHandle( mtd.offsets ); end; end. const hack_pts = 10; type PointArray = array[1..hack_pts] of integer; const hack_points: PointArray = (-100, -100, -100, -100, -100, 800, 800, 800, 800, 800); var hack_pt: integer; hack: boolean; function HackStillDown: boolean; begin if hack then begin HackStillDown := hack_pt <= hack_pts; end else begin HackStillDown := StillDown; end; end; procedure HackGetMouse( var pt: Point ); begin if hack then begin Assert( hack_pt <= hack_pts ); pt.v := hack_points[hack_pt]; Inc(hack_pt); end else begin GetMouse( pt ); end; end;