-- Copyright (C) 1983  by Xerox Corporation. All rights reserved. 
-- DisplayImplC.mesa - last edited by 
-- Rick	        29-Nov-83 11:51:53  
-- Bruce	25-Feb-83 10:35:50  

DIRECTORY
  BitBlt USING [BitBltFlags],
  Display USING [paintGrayFlags],
  DisplayFormat USING [CircleType],
  DisplayOps USING [LogError],
  DisplayInternal USING [SpecialCircle],
  SpecialDisplay USING [defaultContext, LineStyle, solid, Special],
  Window USING [Box, BoxHandle, nullBox, Place],
  WindowOps USING [AbsoluteBoxHandle, Bounds, Object, ScreenBox];

DisplayImplC: PROGRAM
  IMPORTS DisplayInternal, DisplayOps, SpecialDisplay, WindowOps
  EXPORTS Display, DisplayInternal, SpecialDisplay, Window =
  BEGIN

  -- exported types
  Handle: TYPE = LONG POINTER TO Object;
  Object: PUBLIC TYPE = WindowOps.Object;

  -- copied types because John doesn't like them
  Special: TYPE = SpecialDisplay.Special;

  Arc: PUBLIC PROC [
    window: Handle, place: Window.Place, radius: INTEGER,
    startSector, stopSector: CARDINAL, start, stop: Window.Place,
    bounds: Window.BoxHandle ← NIL] = {
    IF ~window.inTree THEN RETURN;
    [] ← SpArcInternal[
      window, FALSE, place, radius, startSector, stopSector, start, stop,
      ALL[FALSE], bounds, SpecialDisplay.solid, Display.paintGrayFlags]};

  SpArc: PUBLIC PROC [
    window: Handle, place: Window.Place, radius: INTEGER,
    startSector, stopSector: CARDINAL, start, stop: Window.Place,
    bounds: Window.BoxHandle, dashes: SpecialDisplay.LineStyle, 
    flags: BitBlt.BitBltFlags, context: Special←SpecialDisplay.defaultContext] = {
    ENABLE UNWIND => NULL;
    filled: BOOLEAN = context.alloc # NIL;
    SpArcInternal[
      window, filled, place, radius, startSector, stopSector, start, stop,
      ALL[FALSE], bounds, dashes, flags, context]};

  SpArcInternal: PROC [
    window: Handle, filled: BOOLEAN, place: Window.Place, radius: INTEGER,
    startSector, stopSector: CARDINAL, start, stop: Window.Place, 
    circleType: DisplayFormat.CircleType, bounds: Window.BoxHandle, 
    dashes: SpecialDisplay.LineStyle,
    flags: BitBlt.BitBltFlags, context: Special ← SpecialDisplay.defaultContext]={
    box1, box2, box3: Window.Box ← Window.nullBox;
    boundsBox: WindowOps.ScreenBox = 
      IF bounds = NIL THEN WindowOps.Bounds[window]
      ELSE WindowOps.AbsoluteBoxHandle[window, bounds];
    IF filled THEN FillArcBoxes[
      @box1, @box2, @box3, start, stop, place, radius, boundsBox.top,
      boundsBox.bottom]
    ELSE DisplayArcBoxes[
      @box1, @box2, @box3, start, stop, place, radius, dashes.thickness,
      (startSector-1)*8+(stopSector-1)];  -- octants are now 0..7
    IF box1 # Window.nullBox THEN DisplayInternal.SpecialCircle[
      window: window, place: place, radius: radius, circleType: circleType,
      bounds: @box1, dashes: dashes, flags: flags, context: context];
    IF box2 # Window.nullBox THEN DisplayInternal.SpecialCircle[
      window: window, place: place, radius: radius, circleType: circleType,
      bounds: @box2, dashes: dashes, flags: flags, context: context];
    IF box3 # Window.nullBox THEN DisplayInternal.SpecialCircle[
      window: window, place: place, radius: radius, circleType: circleType,
      bounds: @box3, dashes: dashes, flags: flags, context: context] };
  
  DisplayArcBoxes: PUBLIC PROC [
    b1, b2, b3: Window.BoxHandle, start,stop,center:Window.Place,
    radius, thickness, sum: CARDINAL] = {
    box1, box2, box3: WindowOps.ScreenBox ← [left:0,right:0,top:0,bottom:0];
    bigBox: WindowOps.ScreenBox ← [
      left: center.x - radius - 1, right: center.x + radius + 1,
      top: center.y - radius - 1, bottom: center.y + radius + 1];
    littleBox: WindowOps.ScreenBox ← [
      left: MIN[start.x, stop.x], right: MAX[start.x, stop.x], 
      top: MIN[start.y, stop.y], bottom: MAX[start.y, stop.y]];
    IF thickness > 2 THEN {
      bigBox.left ← bigBox.left - 1;
      bigBox.right ← bigBox.right + 1;
      bigBox.top ← bigBox.top - 1;
      bigBox.bottom ← bigBox.bottom + 1;
      IF littleBox.left < center.x THEN littleBox.left ← littleBox.left - 1;
      IF littleBox.top < center.y THEN littleBox.top ← littleBox.top - 1;
      IF littleBox.right > center.x THEN littleBox.right ← littleBox.right + 1;
      IF littleBox.bottom > center.y THEN littleBox.bottom ← littleBox.bottom+1};
    --sum ← begin*8 + end;   0 to 65, could be passed from the graphic object
    -- convert sum to octal to get start and stop octants
    -- (eg. 14 = 16 octal or start octant 1 stop octant 6)
    SELECT sum FROM
      0 => -- both in octant 0
        IF start.y > stop.y OR start.x > stop.x THEN box1 ← littleBox
	ELSE {
	  box1 ← box2 ← box3 ← bigBox;
	  box1.top ← box2.bottom ← box3.bottom ← center.y;
	  box2.right ← start.x;
	  box3.left ← stop.x};
      1, 2, 57, 58 => { -- 0 to 1, 0 to 2
        box1 ← box2 ← bigBox;
        box1.right ← box2.left ← start.x;
        box2.top ← stop.y};
      3, 4, 59, 60 => {-- 0 to 3, 0 to 4
        box1 ← box2 ← bigBox;
        box1.bottom ← box2.top ← center.y;
	box1.right ← start.x;
        box2.right ← stop.x};
      9 =>  -- both in octant 1
        IF start.y > stop.y OR start.x > stop.x THEN box1 ← littleBox
	ELSE {
	  box1 ← box2 ← box3 ← bigBox;
	  box1.right ← box2.left ← box3.left ← center.x;
	  box2.bottom ← start.y;
	  box3.top ← stop.y};
      10 => {-- 1 to 2
        box1 ← box2 ← box3 ← bigBox;
        box1.right ← box2.left ← box3.left ← center.x;
        box2.bottom ← start.y;
        box3.top ← stop.y}; 
      11, 12, 19, 20 => {
        box1 ← box2 ← bigBox;
        box1.right ← box2.left ← stop.x;
        box2.bottom ← start.y};
      13, 14, 21, 22 => {-- 1 to 5
        box1 ← box2 ← bigBox;
        box1.right ← box2.left ← center.x;
	box1.bottom ← stop.y;
        box2.bottom ← start.y};
      18 =>  -- both in octant 2
        IF start.y > stop.y OR start.x < stop.x THEN box1 ← littleBox
	ELSE {
	  box1 ← box2 ← box3 ← bigBox;
	  box1.right ← box2.left ← box3.left ← center.x;
	  box2.bottom ← start.y;
	  box3.top ← stop.y};
      24, 31, 32, 39 => {
	box1 ← box2 ← bigBox;
        box1.top ← box2.bottom ← center.y;
	box1.left ← start.x;
        box2.left ← stop.x};
      27 =>  -- both in octant 3
        IF start.y > stop.y OR start.x < stop.x THEN box1 ← littleBox
	ELSE {
	  box1 ← box2 ← box3 ← bigBox;
	  box1.bottom ← box2.top ← box3.top ← center.y;
	  box2.left ← start.x;
	  box3.right ← stop.x};
      28 => {
        box1 ← box2 ← box3 ← bigBox;
        box1.bottom ← box2.top ← box3.top ← center.y;
        box2.left ← start.x;
        box3.right ← stop.x};
      29, 30, 37, 38 => {
        box1 ← box2 ← bigBox;
        box1.left ← box2.right ← start.x;
        box2.bottom ← stop.y};
      36 =>  -- both in octant 4
        IF start.y < stop.y OR start.x < stop.x THEN box1 ← littleBox
	ELSE {
	  box1 ← box2 ← box3 ← bigBox;
	  box1.bottom ← box2.top ← box3.top ← center.y;
	  box2.left ← start.x;
	  box3.right ← stop.x};
      40, 47, 48, 55 => {
        box1 ← box2 ← bigBox;
        box1.left ← box2.right ← stop.x;
        box2.top ← start.y};
      41, 42, 49, 50 => {
        box1 ← box2 ← bigBox;
        box1.left ← box2.right ← center.x;
        box2.top ← start.y;
	box1.top ← stop.y};
      45 =>  -- both in octant 5
        IF start.y < stop.y OR start.x < stop.x THEN box1 ← littleBox
	ELSE {
	  box1 ← box2 ← box3 ← bigBox;
	  box1.left ← box2.right ← box3.right ← center.x;
	  box2.top ← start.y;
	  box3.bottom ← stop.y};
      46 => {
        box1 ← box2 ← box3 ← bigBox;
        box1.left ← box2.right ← box3.right ← center.x;
        box2.top ← start.y;
        box3.bottom ← stop.y};
      54 =>  -- both in octant 6
        IF start.y < stop.y OR start.x > stop.x THEN box1 ← littleBox
	ELSE {
	  box1 ← box2 ← box3 ← bigBox;
	  box1.left ← box2.right ← box3.right ← center.x;
	  box2.top ← start.y;
	  box3.bottom ← stop.y};
      56 => {
        box1 ← box2 ← box3 ← bigBox;
        box1.top ← box2.bottom ← box3.bottom ← center.y;
        box2.right ← start.x;
        box3.left ← stop.x};
      63 =>  -- both in octant 7
        IF start.y < stop.y OR start.x > stop.x THEN box1 ← littleBox
	ELSE {
	  box1 ← box2 ← box3 ← bigBox;
        box1.top ← box2.bottom ← box3.bottom ← center.y;
        box2.right ← start.x;
        box3.left ← stop.x};
      5, 61 => {
        box1 ← bigBox;
	box1.right ← start.x;
	box1.bottom ← stop.y};
      6, 7, 15 => {
        box1 ← littleBox;
	box1.top ← bigBox.top};
      23 => {
        box1 ← bigBox;
	box1.left ← stop.x;
	box1.bottom ← start.y};
      16, 17, 25 => {
        box1 ← littleBox;
	box1.right ← bigBox.right};
      33, 34 => {
        box1 ← littleBox;
	box1.right ← bigBox.right;
	box1.bottom ← bigBox.bottom};
      35, 43 => {
        box1 ← littleBox;
	box1.bottom ← bigBox.bottom};
      51, 52 => {
        box1 ← littleBox;
	box1.left ← bigBox.left;
	box1.bottom ← bigBox.bottom};
      53 => {
        box1 ← littleBox;
	box1.left ← bigBox.left};
      ENDCASE => box1 ← littleBox;	--8, 26, 44, 62 
        
    IF box1.top < box1.bottom AND box1.left < box1.right THEN b1↑ ← [
      place: [x: box1.left, y: box1.top],
      dims: [w: box1.right - box1.left + 1, h: box1.bottom - box1.top + 1]];
    IF box2.top < box2.bottom AND box2.left < box2.right THEN b2↑ ← [
      place: [x: box2.left, y: box2.top],
      dims: [w: box2.right - box2.left + 1, h: box2.bottom - box2.top + 1]];
    IF box3.top < box3.bottom AND box3.left < box3.right THEN b3↑ ← [
      place: [x: box3.left, y: box3.top],
      dims: [w: box3.right - box3.left + 1, h: box3.bottom - box3.top + 1]]};
        
  FillArcBoxes: PUBLIC PROC [
    b1, b2, b3: Window.BoxHandle, startPlace, stopPlace, centerPlace:
    Window.Place, screenRadius, top, bottom: INTEGER] = {
    left: INTEGER = centerPlace.x - screenRadius - 1;
    right: INTEGER = centerPlace.x + screenRadius + 1;
    sum: CARDINAL ← (SELECT TRUE FROM
      startPlace.x < centerPlace.x => 0,
      startPlace.x = centerPlace.x AND startPlace.y > centerPlace.y => 1,
      startPlace.x = centerPlace.x AND startPlace.y < centerPlace.y => 2,
      ENDCASE => 3) +
     (SELECT TRUE FROM
        stopPlace.x < centerPlace.x => 0,
        stopPlace.x = centerPlace.x AND stopPlace.y > centerPlace.y => 4,
        stopPlace.x = centerPlace.x AND stopPlace.y < centerPlace.y => 8,
        ENDCASE => 12);
    IF startPlace.y > stopPlace.y THEN sum ← sum + 16;
    SELECT sum FROM
      0, 2, 4, 6 => b1↑ ← [place: [x: left, y: startPlace.y],
	dims: [w: centerPlace.x - left + 1, h: stopPlace.y - startPlace.y + 1]];
      11, 13, 25, 27, 29, 31 => b1↑ ← [place: [x: centerPlace.x, y:stopPlace.y],
        dims: [w: right - centerPlace.x + 1, h:startPlace.y - stopPlace.y + 1]];         8, 10, 12, 14, 24, 28 => {
	b1↑ ← [place: [x: left, y: startPlace.y],
	  dims: [w: centerPlace.x - left + 1, h: bottom - startPlace.y + 1]];
	b2↑ ← [place: [x: centerPlace.x, y: stopPlace.y],
	  dims: [w: right - centerPlace.x + 1, h: bottom - stopPlace.y + 1]]};
      1, 3, 5, 7, 17, 19 => {
        b1↑ ← [place: [x: left, y: top],
	  dims: [w: centerPlace.x - left + 1, h: stopPlace.y - top + 1]];
	b2↑ ← [place: [x: centerPlace.x, y: top],
	  dims: [w: right - centerPlace.x + 1, h: startPlace.y - top + 1]]};
      15 => {
        b1↑ ← [place: [x: left, y: top],
	  dims: [w: centerPlace.x - left + 1, h: bottom - top + 1]];
	b2↑ ← [place: [x: centerPlace.x, y: top],
	  dims: [w: right - centerPlace.x + 1, h: startPlace.y - top + 1]];
	b3↑ ← [place: [x: centerPlace.x, y: stopPlace.y],
	  dims: [w: right - centerPlace.x + 1, h: bottom - stopPlace.y + 1]]};
      16 => {
        b1↑ ← [place: [x: centerPlace.x, y: top],
	  dims: [w: right - centerPlace.x + 1, h: bottom - top + 1]];
	b2↑ ← [place: [x: left, y: startPlace.y],
	  dims: [w: centerPlace.x - left + 1, h: bottom - startPlace.y + 1]];
	b3↑ ← [place: [x: left, y: top],
	  dims: [w: centerPlace.x - left + 1, h: stopPlace.y - top + 1]]};
      ENDCASE => {
        DisplayOps.LogError[]; 
	RETURN};
    IF b1↑ # Window.nullBox AND b1.dims.h = 1 AND
      (b2↑ # Window.nullBox OR b3↑ # Window.nullBox) THEN 
      b1↑ ← Window.nullBox;
    IF b2↑ # Window.nullBox AND b2.dims.h = 1 AND
      (b1↑ # Window.nullBox OR b3↑ # Window.nullBox) THEN 
      b2↑ ← Window.nullBox;
    IF b3↑ # Window.nullBox AND b3↑.dims.h = 1 AND
      (b1↑ # Window.nullBox OR b2↑ # Window.nullBox) THEN 
      b3↑ ← Window.nullBox};

  END.