#import "NuText.h"
#import "Nutation.h"
#import <appkit/Text.h>
#import <appkit/nextstd.h>
#import <dpsclient/psops.h>
#import <dpsclient/dpsclient.h>
#import <appkit/NXCursor.h>


 // RTFGlyph provides an rtf glyph.  You
 // edit the text by double-clicking on the
 // glyph, which sends you into "editing mode".
 // Clicking outside the glyph exits editing mode.
 // The glyph does not resize its text when its
 // boundaries are changed...instead, it "rewraps"
 // it.
 // Superclass file goes on next line:
#pragma .h #import "BMPriv_.h"
@implementation RTFGlyph:BMPriv_
{ char *textString ;
}

- copy ;
{ // if non-Null, make a copy of textString
  id aCopy ;
  aCopy = [super copy] ;
  if(textString)
  { aCopy->textString = malloc(strlen(textString)+1) ;
    strcpy(aCopy->textString,textString);
  }
  return aCopy ;  
}

- draw: (NXSize *) scale ;
{ // cause the Text to be redrawn.  The
  // code is very similar to the mouseDown: code...
  // the difference is, with mouseDown, we enter
  // an "editing" mode, attaching the Text object
  // to the glyphview.  Here we just send drawSelf
  // to Text, after flipping the coordinate
  // axes.  Would be nice to use the field editor, but
  // it always has an opaque background...there is no
  // method to change it...argh!
  id textView, flipView ; 
  NXStream *stream;
  NXRect aRect,bRect ;
  if(!textString) // no text...nothing to display
    return self ;
  textView = [Text new] ;
  [textView setFont:[[FontManager new] selFont]];
  // Modify it so that it will edit Rich Text and use the FontPanel.
  [textView setCharFilter:NXEditorFilter];
  [textView setFontPanelEnabled:YES];
  [textView setMonoFont:NO];
  [self getTextFrame: &aRect] ;
  bRect = aRect ;
  bRect.origin.x = bRect.origin.y = 0.0 ;
  [textView setFrame:&bRect]; 
  // Use existing text, if any
  if(textString)
  { stream = NXOpenMemory(textString, strlen(textString), NX_READONLY);
    [textView readRichText:stream];
    NXCloseMemory(stream, NX_SAVEBUFFER);
  }
  else
  { [textView setText:""];
    [textView setAlignment:NX_LEFTALIGNED];
    [textView unscript:self];
  }
  // now grab the image. Note: focus is locked on
  // our bitmap.  We must also "flip" the view, which we
  // do here by changing the postscript ctm.
  PSgsave() ;
  PStranslate(aRect.origin.x,aRect.origin.y) ; 
  NuClearRect(&aRect) ;
  DPSPrintf(DPSGetCurrentContext(),
    "/saveMatrix matrix currentmatrix def "
    "[1 0 0 -1 0 0] concat 0.0 -%f translate ",
        aRect.size.height) ;
  [textView drawSelf: &bRect :1] ;
  PSgrestore() ; 
  [textView free] ;
  return self ;
}

- endEditing ;
{ // go out of "editing mode"
  if(flags.user1) // this flag is set when in "editing mode"
  { // store fieldEditor's text and remove it
    // from the hierarchy
    int length, maxlen;
    char *buffer;
    NXStream *stream;
    id textView, flipView, aWin ;
    NXRect aRect ;
    aWin = [[Nu glyphView] window] ;
    textView = [aWin getFieldEditor:YES for:self];
    if(textString) 
    { // free up the old text
      free(textString);
      textString = NULL;
    }
    if([textView textLength])
    { // save the new text
      stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
      [textView writeRichText:stream];
      NXGetMemoryBuffer(stream, &buffer, &length, &maxlen);
      textString = (char *) malloc(length + 1) ;
      bcopy(buffer, textString, length);
      textString[length] = '\0' ; // make sure null-terminated!
      NXCloseMemory(stream, NX_FREEBUFFER);
    }
    // remove flipView and textView from hierarchy, free the flipView
    flipView = [textView superview] ;
    [aWin endEditingFor: self] ;
    [[flipView removeFromSuperview] free];
    flags.user1 = NO ;
    // now blit the bits into my image
    [aWin disableFlushWindow] ; // get rid of extra flush
    [self didResize: self] ; // forces redraw of bitmap, then 
    [self resignTarget] ;  // force forground to display 
    [self becomeTarget] ;  // new bitmap
    [aWin reenableFlushWindow] ;
    [self getTextFrame: &aRect] ;
    [self convertToRootGlyph: &aRect.origin] ;
    [[Nu rootGlyph] display: &aRect fromView: nil] ; // updates onscreen display
    [aWin enableCursorRects] ;
    [NXIBeam pop] ;
    [aWin addToEventMask: NX_RMOUSEDOWNMASK | NX_RMOUSEDRAGGEDMASK |
       NX_RMOUSEUPMASK] ;
   }
  return self ;
}

- free ;
{ if(textString)
    free(textString) ;
  return [super free] ;
}

- getTextFrame: (NXRect *) aRect ;
{ // sets aRect to the frame rectangle in which the
  // text will be drawn, in my coord sys.  For NuText,
  // this frame is the same as my frame, but subclasses
  // may redefine 
  *aRect = frame ;
  aRect->origin.x = aRect->origin.y = 0.0 ;
  return self ;
}


- mouseUp: (NXEvent *) anEvent ;
{ // if this is a double-click, then go into
  // editing "mode"...i.e. use a text object
  // to edit the text
  NXSize maxSize;
  NXStream *stream;
  NXRect aRect, bRect ;
  // create and attach a text object (we actually
  // use the field editor here)
  if(anEvent->data.mouse.click == 2 && !flags.user1)
  { id textView, flipView, aWin ;
    aWin = [[Nu glyphView] window] ;
    [aWin endEditingFor:self];
    textView = [aWin getFieldEditor:YES for:self]; 
    [textView setFont:[[FontManager new] selFont]];
    // Modify it so that it will edit Rich Text and use the FontPanel.
    [textView setCharFilter:NXEditorFilter];
    [textView setFontPanelEnabled:YES];
    [textView setMonoFont:NO];
    [textView setOpaque:YES];
    [self getTextFrame: &aRect] ;
    bRect = aRect ;
    bRect.origin.x = bRect.origin.y = 0.0 ;
    [textView setFrame:&bRect]; 
    // Use existing text, if any
    if(textString)
    { stream = NXOpenMemory(textString, strlen(textString), NX_READONLY);
      [textView readRichText:stream];
      NXCloseMemory(stream, NX_SAVEBUFFER);
    }
    else
    { [textView setText:""];
      [textView setAlignment:NX_LEFTALIGNED];
      [textView unscript:self];
    }
    [textView setSel: 0 :0] ;
    // Add a flipped view (to hold the textView) to view hierarchy
    // ....change frame to aRect translated
    [self convertToRootGlyph: &aRect.origin] ;
    flipView = [[View alloc] initFrame: &aRect] ;
    [flipView setFlipped: YES] ;
    [[Nu glyphView] addSubview:flipView];
    // Add textView to view heirarchy, make it firstReponder 
    [flipView addSubview:textView];
    [aWin makeFirstResponder:textView];
    flags.user1 = YES ;
    [textView display] ;
    // give it the text cursor
    [aWin disableCursorRects] ;
    [NXIBeam push] ;
    // disable all right mouse events
    [aWin removeFromEventMask: NX_RMOUSEDOWNMASK | NX_RMOUSEDRAGGEDMASK |
       NX_RMOUSEUPMASK] ;
  }
  return [super mouseUp: anEvent] ;
}

 
- resignTarget; 
{ [self endEditing] ;
  return [super resignTarget] ; 
}

- (char *) text ;
{ // returns a pointer to a malloc'ed text string
  // containing this object's text, de-rtf'ed.  Caller
  // is responsible for freeing the pointer.
  id textView ;
  char *aString, *buffer ;
  int length, maxlen ;
  NXStream *stream ;
  textView = [Text new] ;
  if(textString)
  { stream = NXOpenMemory(textString, strlen(textString), NX_READONLY);
    [textView readRichText:stream];
    NXCloseMemory(stream, NX_FREEBUFFER);
  }
  else
    [textView setText:""];
  stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  [textView writeText:stream];
  NXGetMemoryBuffer(stream, &buffer, &length, &maxlen);
  aString = (char *) malloc(length + 1) ;
  bcopy(buffer, aString, length);
  aString[length] = '\0' ; // make sure null-terminated!
  NXCloseMemory(stream, NX_FREEBUFFER);
  [textView free] ;
  return aString ;
}

-read: (NXTypedStream *) stream ;
{ [super read: stream] ;
  NXReadType(stream, "*", &textString) ;
  return self ;
}

-write: (NXTypedStream *) stream ;
{ [super write: stream] ;
  NXWriteType(stream, "*", &textString)  ;
  return self ;
}

@end
