home *** CD-ROM | disk | FTP | other *** search
/ World of A1200 / World_Of_A1200.iso / programs / workbench / stickit2 / source.lha / source / carat.c next >
C/C++ Source or Header  |  1995-01-09  |  14KB  |  595 lines

  1. /*********************************************
  2.  **************   carat.c   ******************
  3.  *********************************************/
  4.  
  5. #define INTUI_V36_NAMES_ONLY
  6.  
  7. #include <exec/exec.h>
  8. #include <intuition/intuition.h>
  9. #include <graphics/gfxmacros.h>
  10. #include <graphics/rastport.h>
  11.  
  12. #include <clib/exec_protos.h>
  13. #include <clib/intuition_protos.h>
  14. #include <clib/graphics_protos.h>
  15. #include <clib/console_protos.h>
  16. #include <clib/gadtools_protos.h>
  17.  
  18. #include <stdio.h>
  19. #include <string.h>
  20.  
  21. #include "stickit2.h"
  22.  
  23. #include "consts.h"
  24. #include "structs.h"
  25. #include "proto.h"
  26.  
  27. extern prj_p prj;
  28.  
  29. int carat_line_from_carat(note_p,char *);
  30.  
  31. /*
  32. Function : void carat_from_coords(note_p curr_note,WORD x_ord,WORD y_ord)
  33. Purpose : Called by the notes event handler. Given a note and the co-ordinates
  34.     of where the user has clicked this function will position the
  35.     curr_note->carat.text pointer to point to the correct character in the
  36.     text string. To draw the carat at the correct position, use
  37.     carat_draw().
  38. */
  39.  
  40. void carat_from_coords(note_p curr_note,WORD x_ord,WORD y_ord)
  41. {
  42.     struct Window *curr_win;
  43.     struct RastPort *curr_rport;
  44.     struct TextExtent textextent_result;
  45.  
  46.     char *text_ptr;
  47.  
  48.     ULONG remaininglength;
  49.     LONG textbaseline,topoffset;
  50.     LONG textfit = 0;
  51.     LONG curr_x,curr_mid_x,prev_x,prev_mid_x;
  52.  
  53.     int l;
  54.  
  55.     BOOL validclick = TRUE;
  56.  
  57.     /* Set up some easy references */
  58.  
  59.     curr_win = curr_note->win;
  60.     curr_rport = curr_win->RPort;
  61.  
  62.     textbaseline = curr_rport->TxBaseline + NO_INTERLINE_PIXELS;
  63.     topoffset = curr_win->WScreen->BarHeight + 1;
  64.  
  65.     /* See if user clicked in valid region */
  66.  
  67.     if ((x_ord < curr_win->BorderLeft) ||
  68. (x_ord > (curr_win->Width - curr_win->BorderRight)))
  69.         return;
  70.  
  71.     if ((y_ord < curr_win->BorderTop) ||
  72. (y_ord > (curr_win->Height - curr_win->BorderBottom)))
  73.         return;
  74.  
  75.     /* Set up the text pointer */
  76.  
  77.     text_ptr = curr_note->text;
  78.  
  79.     /* Move to position */
  80.  
  81.     Move(curr_rport,(LONG)curr_win->BorderLeft,topoffset + textbaseline);
  82.  
  83.     while(strlen(text_ptr)) {
  84.  
  85.         /* Have we reached the bottom ? */
  86.  
  87.         if ((curr_rport->cp_y + (curr_rport->TxHeight - textbaseline))>
  88. (curr_win->Height - (curr_win->BorderBottom + 2))) {
  89.             validclick = FALSE;
  90.             break;
  91.         }
  92.  
  93.         /* Remove any space */
  94.  
  95.         for (l = 0; (text_ptr[l] == ' ') &&(l < strlen(text_ptr)); l++);
  96.  
  97.         text_ptr += l;
  98.  
  99.         /* How much text will fit on ? */
  100.  
  101.         textfit = TextFit(curr_rport,text_ptr,
  102. strlen(text_ptr),&textextent_result,NULL,1,(LONG)curr_win->Width -
  103. (curr_rport->cp_x + curr_win->BorderLeft + curr_win->BorderRight + CARAT_WIDTH),
  104. curr_rport->TxHeight + 1);
  105.  
  106.         /* If no text will be printed, try next line */
  107.  
  108.         if (textfit == 0) {
  109.             Move(curr_rport,curr_win->BorderLeft,
  110. curr_rport->cp_y + curr_rport->TxHeight + NO_INTERLINE_PIXELS);
  111.             continue;
  112.         }
  113.  
  114.         /* Will I print all the remainining text ? */
  115.  
  116.         remaininglength = strlen(text_ptr);
  117.  
  118.         if (textfit != remaininglength) {
  119.             for (l = textfit;((l > 0) &&(text_ptr[l] != ' ')); l--);
  120.  
  121.             /* If we can successfully wrap it */
  122.  
  123.             if (l != 0)
  124.                 textfit = l + 1;
  125.         }
  126.  
  127.         /* textfit now holds the number of characters to be printed */
  128.         /* See if on this line. */
  129.  
  130.         if (y_ord <= (curr_rport->cp_y + (curr_rport->TxHeight -
  131. textbaseline)))
  132.             break;
  133.  
  134.         /* Next line */
  135.  
  136.         Move(curr_rport,curr_win->BorderLeft,
  137. curr_rport->cp_y + curr_rport->TxHeight + NO_INTERLINE_PIXELS);
  138.  
  139.         /* If we've finished */
  140.  
  141.         if (textfit == remaininglength) {
  142.             validclick = FALSE;
  143.             break;
  144.         }
  145.  
  146.         /* Else, set up next line pointer */
  147.  
  148.         text_ptr += textfit;
  149.     }
  150.  
  151.     if (!validclick)
  152.         return;
  153.  
  154.     /* text_ptr now points to the start of the line the user clicked on */
  155.  
  156.     prev_x = (LONG)curr_win->BorderLeft;
  157.     prev_mid_x = (LONG)curr_win->BorderLeft - 1;
  158.  
  159.     for (l = 1; l <= textfit; l++) {
  160.         curr_x = TextLength(curr_rport,text_ptr,l) +
  161. (LONG)curr_win->BorderLeft;
  162.         
  163.         curr_mid_x = prev_x + (curr_x - prev_x) / 2;
  164.  
  165.         if ((x_ord > prev_mid_x) && (x_ord <= curr_mid_x)) {
  166.             curr_note->carat.text = text_ptr + l - 1;
  167.  
  168.             /* Store old carat positions */
  169.  
  170.             curr_note->carat.oldxpos = curr_note->carat.xpos;
  171.             curr_note->carat.oldypos = curr_note->carat.ypos;
  172.  
  173.             curr_note->carat.xpos = prev_x;
  174.             curr_note->carat.ypos = curr_rport->cp_y - textbaseline + 2;
  175.  
  176.             carat_draw(curr_note);
  177.  
  178.             return;
  179.         }
  180.  
  181.         prev_x = curr_x;
  182.         prev_mid_x = curr_mid_x;
  183.     }
  184.  
  185.     /* It must lie at the end of the line */
  186.  
  187.     curr_note->carat.text = text_ptr + textfit;
  188.  
  189.     /* Store old carat positions */
  190.  
  191.     curr_note->carat.oldxpos = curr_note->carat.xpos;
  192.     curr_note->carat.oldypos = curr_note->carat.ypos;
  193.  
  194.     curr_note->carat.xpos = prev_x;
  195.     curr_note->carat.ypos = curr_rport->cp_y - textbaseline + 2;
  196.  
  197.     carat_draw(curr_note);
  198. }
  199.  
  200. /*
  201. Function : void carat_draw(note_p curr_note)
  202. Purpose : Will draw the carat in the current note window. It takes the values
  203.     from curr_note->carat.xpos etc... If the values of oldxpos etc...
  204.     are valid, the old carat is removed by XORing.
  205. */
  206.  
  207. void carat_draw(note_p curr_note)
  208. {
  209.     struct Window *curr_win;
  210.     struct RastPort *curr_rport;
  211.  
  212.     LONG textbaseline;
  213.  
  214.     /* Shortcuts */
  215.  
  216.     curr_win = curr_note->win;
  217.     curr_rport = curr_win->RPort;
  218.  
  219.     textbaseline = curr_rport->TxBaseline + NO_INTERLINE_PIXELS;
  220.  
  221.     /* Set draw modes */
  222.  
  223.     SetDrMd(curr_rport,COMPLEMENT);
  224.     SetAPen(curr_rport,curr_note->caratcolour);
  225.     SetBPen(curr_rport,curr_note->caratcolour);
  226.  
  227.     /* Undraw the old one, if it exists */
  228.  
  229.     if (curr_note->carat.oldxpos)
  230.         RectFill(curr_rport,curr_note->carat.oldxpos,
  231. curr_note->carat.oldypos,curr_note->carat.oldxpos + CARAT_WIDTH,
  232. curr_note->carat.oldypos + curr_rport->TxHeight - 1);
  233.  
  234.     /* Draw new one */
  235.  
  236.     if (curr_note->carat.xpos)
  237.         RectFill(curr_rport,curr_note->carat.xpos,
  238. curr_note->carat.ypos,curr_note->carat.xpos + CARAT_WIDTH,
  239. curr_note->carat.ypos + curr_rport->TxHeight - 1);
  240. }
  241.  
  242. /*
  243. Function : void carat_clear(note_p curr_note)
  244. Purpose : Clears all the info for the carat. This "undraws" the carat from
  245.     the window.
  246. */
  247.  
  248. void carat_clear(note_p curr_note)
  249. {
  250.     struct Window *curr_win;
  251.     struct RastPort *curr_rport;
  252.  
  253.     LONG textbaseline;
  254.  
  255.     /* Shortcuts */
  256.  
  257.     curr_win = curr_note->win;
  258.     curr_rport = curr_win->RPort;
  259.  
  260.     textbaseline = curr_rport->TxBaseline + NO_INTERLINE_PIXELS;
  261.  
  262.     /* Set draw modes */
  263.  
  264.     SetDrMd(curr_rport,COMPLEMENT);
  265.     SetAPen(curr_rport,curr_note->caratcolour);
  266.     SetBPen(curr_rport,curr_note->caratcolour);
  267.  
  268.     /* Undraw the current one, if it exists */
  269.  
  270.     if (curr_note->carat.xpos)
  271.         RectFill(curr_rport,curr_note->carat.xpos,
  272. curr_note->carat.ypos,curr_note->carat.xpos + CARAT_WIDTH,
  273. curr_note->carat.ypos + curr_rport->TxHeight - 1);
  274.  
  275.     curr_note->carat.xpos = curr_note->carat.ypos = 0;
  276.     curr_note->carat.oldxpos = curr_note->carat.oldypos = 0;
  277.     curr_note->carat.text = NULL;
  278. }
  279.  
  280. /*
  281. Function : void carat_from_ptr(note_p curr_note,int ptrchange)
  282. Purpose : Given the curr_note->carat.text pointer, will place the carat in the
  283.     correct position in the window. Set ptrchange to PTRCHANGE_CLICK if
  284.     the carat position is being changed due to a mouse click,
  285.     PTRCHANGE_CURSOR if it because the user has used the cursor keys.
  286. */
  287.  
  288. void carat_from_ptr(note_p curr_note,int ptrchange)
  289. {
  290.     struct Window *curr_win;
  291.     struct RastPort *curr_rport;
  292.     struct TextExtent textextent_result;
  293.  
  294.     char *text_ptr;
  295.  
  296.     ULONG remaininglength;
  297.     LONG topoffset,textbaseline;
  298.     LONG textfit;
  299.  
  300.     int l;
  301.  
  302.     BOOL foundline = TRUE;
  303.  
  304.     /* Shortcuts */
  305.  
  306.     curr_win = curr_note->win;
  307.     curr_rport = curr_win->RPort;
  308.  
  309.     textbaseline = curr_rport->TxBaseline + NO_INTERLINE_PIXELS;
  310.     topoffset = curr_win->WScreen->BarHeight + 1;
  311.  
  312.     /* Set up the text pointer */
  313.  
  314.     text_ptr = curr_note->text;
  315.  
  316.     /* If we are cursoring to the end */
  317.  
  318.     if (*curr_note->carat.text == '\0')
  319.         ptrchange = 1;
  320.  
  321.     /* Move to position */
  322.  
  323.     Move(curr_rport,(LONG)curr_win->BorderLeft,
  324. topoffset + textbaseline);
  325.  
  326.     while(strlen(text_ptr)) {
  327.  
  328.         /* Have we reached the bottom ? */
  329.  
  330.         if ((curr_rport->cp_y + (curr_rport->TxHeight - textbaseline))>
  331. (curr_win->Height - (curr_win->BorderBottom + 2))) {
  332.             foundline = FALSE;
  333.             break;
  334.         }
  335.  
  336.         /* Remove any space */
  337.  
  338.         for (l = 0; (text_ptr[l] == ' ') &&(l < strlen(text_ptr)); l++);
  339.  
  340.         text_ptr += l;
  341.  
  342.         /* How much text will fit on ? */
  343.  
  344.         textfit = TextFit(curr_rport,text_ptr,
  345. strlen(text_ptr),&textextent_result,NULL,1,(LONG)curr_win->Width -
  346. (curr_rport->cp_x + curr_win->BorderLeft + curr_win->BorderRight + CARAT_WIDTH),
  347. curr_rport->TxHeight + 1);
  348.  
  349.         /* If no text will be printed, try next line */
  350.  
  351.         if (textfit == 0) {
  352.             Move(curr_rport,curr_win->BorderLeft,
  353. curr_rport->cp_y + curr_rport->TxHeight + NO_INTERLINE_PIXELS);
  354.             continue;
  355.         }
  356.  
  357.         /* Will I print all the remainining text ? */
  358.  
  359.         remaininglength = strlen(text_ptr);
  360.  
  361.         if (textfit != remaininglength) {
  362.             for (l = textfit;((l > 0) &&(text_ptr[l] != ' ')); l--);
  363.  
  364.             /* If we can successfully wrap it */
  365.  
  366.             if (l != 0)
  367.                 textfit = l + 1;
  368.         }
  369.  
  370.         /* textfit now holds the number of characters to be printed */
  371.         /* See if on this line. */
  372.  
  373.         if ((curr_note->carat.text >= text_ptr) &&
  374. ((curr_note->carat.text < text_ptr + textfit + ptrchange)))
  375.             break;
  376.  
  377.         /* Next line */
  378.  
  379.         Move(curr_rport,curr_win->BorderLeft,
  380. curr_rport->cp_y + curr_rport->TxHeight + NO_INTERLINE_PIXELS);
  381.  
  382.         /* If we've finished */
  383.  
  384.         if (textfit == remaininglength) {
  385.             foundline = FALSE;
  386.             break;
  387.         }
  388.  
  389.         /* Else, set up next line pointer */
  390.  
  391.         text_ptr += textfit;
  392.     }
  393.  
  394.     if (!foundline)
  395.         return;
  396.  
  397.     /* text_ptr points to the start of the line of text */
  398.  
  399.     /* Pretend we've clicked in the window at the calculated position */
  400.  
  401.     carat_from_coords(curr_note,(WORD)(TextLength(curr_rport,text_ptr,
  402. curr_note->carat.text - text_ptr) + curr_win->BorderLeft),
  403. curr_rport->cp_y);
  404. }
  405.  
  406. /*
  407. Function : void carat_vanillakey(note_p curr_note,struct IntuiMessage *curr_msg)
  408. Purpose : This is the routine that is called when the user types some text
  409.     into the note. It contains any character that can be described as a
  410.     vanilla key.
  411. */
  412.  
  413. void carat_vanillakey(note_p curr_note,struct IntuiMessage *curr_msg)
  414. {
  415.     carat_addachar(curr_note,(char)curr_msg->Code,TRUE);
  416.  
  417.     prj->projectchanged = TRUE;
  418. }
  419.  
  420. /*
  421. Function : void carat_rawkey(note_p curr_note,struct IntuiMessage *curr_msg)
  422. Purpose : This is the routine that is called when the user types some text
  423.     into the note. It contains any character that can't be described as a
  424.     vanilla key (ie cursor keys).
  425. */
  426.  
  427. void carat_rawkey(note_p curr_note,struct IntuiMessage *curr_msg)
  428. {
  429.     struct InputEvent *ievent;
  430.     struct Window *curr_win;
  431.     struct RastPort *curr_rport;
  432.  
  433.     UBYTE buffer[SIZE_RAWKEYBUFFER];
  434.     LONG textbaseline;
  435.     LONG actual;
  436.  
  437.     /* Set up some easy reference */
  438.  
  439.     curr_win = curr_note->win;
  440.     curr_rport = curr_win->RPort;
  441.  
  442.     textbaseline = curr_rport->TxBaseline + NO_INTERLINE_PIXELS;
  443.  
  444.     /* Alloc some temporary buffer memory */
  445.  
  446.     ievent = AllocMem(sizeof (struct InputEvent),MEMF_CLEAR);
  447.  
  448.     if (!ievent)    /* Can't allocate structure */
  449.         return;
  450.  
  451.     ievent->ie_Class = IECLASS_RAWKEY;
  452.     ievent->ie_Code = curr_msg->Code;
  453.     ievent->ie_Qualifier = curr_msg->Qualifier;
  454.     ievent->ie_position.ie_addr = *((APTR *)curr_msg->IAddress);
  455.  
  456.     if (!(curr_msg->Code & 0x80)) {
  457.         /* Key down */
  458.  
  459.         actual = RawKeyConvert(ievent,buffer,SIZE_RAWKEYBUFFER-1,NULL);
  460.  
  461.         if ((actual == 2) && (buffer[0] = 155)){
  462.             switch(buffer[1]) {
  463.                 case 'D':    /* Left */
  464.                     if (curr_note->carat.text > 
  465. curr_note->text) {
  466.                         curr_note->carat.text--;
  467.  
  468.                         carat_from_ptr(curr_note,
  469. PTRCHANGE_CURSOR);
  470.                     }
  471.                     break;
  472.                 case 'C':    /* Right */
  473.                     if (*curr_note->carat.text != '\0') {
  474.                         curr_note->carat.text++;
  475.  
  476.                         carat_from_ptr(curr_note,
  477. PTRCHANGE_CURSOR);
  478.                     }
  479.                     break;
  480.                 case 'A':    /* Up */
  481.                     carat_from_coords(curr_note,
  482. (WORD)curr_note->carat.xpos,(WORD)(curr_note->carat.ypos - NO_INTERLINE_PIXELS
  483. - 2));
  484.  
  485.                     break;
  486.                 case 'B':    /* Down */
  487.                     carat_from_coords(curr_note,
  488. (WORD)curr_note->carat.xpos,(WORD)(curr_note->carat.ypos +
  489. curr_rport->TxHeight + 1));
  490.  
  491.                     break;
  492.                 default:    /* Who knows? */
  493.                     break;
  494.             }
  495.         }
  496.     }
  497.  
  498.     FreeMem(ievent,sizeof(struct InputEvent));
  499. }
  500.  
  501. /*
  502. Function : void carat_addachar(note_p curr_note,char c,BOOL redraw)
  503. Pupose : When given a characer, will add the character to the note and refresh
  504.     it. If redraw is TRUE, the note is refresh (ie the user is typing into
  505.     the note) else the note is note refreshed (ie the user has pasted data
  506.     into the note.
  507. */
  508.  
  509. void carat_addachar(note_p curr_note,char c,BOOL redraw)
  510. {
  511.     struct Window *curr_win;
  512.     struct RastPort *curr_rport;
  513.     struct TextFont *curr_font;
  514.  
  515.     if (!curr_note)
  516.         return;
  517.  
  518.     curr_win = curr_note->win;
  519.  
  520.     if (!curr_win)
  521.         return;        /* The window's not open */
  522.  
  523.     curr_rport = curr_win->RPort;
  524.     curr_font = curr_rport->Font;
  525.  
  526.     /* Is the character un-printable ? */
  527.  
  528.     if ((c != '\b') && (c != '\r') && (c != 127) && (c != '\t')) {
  529.         if (((UBYTE)c < curr_font->tf_LoChar) || ((UBYTE)c > curr_font->tf_HiChar)) {
  530.             return;
  531.         }
  532.     }
  533.  
  534.     if (c == '\b') {
  535.         if (curr_note->carat.text > curr_note->text) {
  536.             remove_char_from_string(curr_note->carat.text - 1);
  537.  
  538.             curr_note->carat.text--;
  539.  
  540.             if (redraw) {
  541.                 carat_from_ptr(curr_note,PTRCHANGE_CLICK);
  542.                 note_refresh(curr_note);
  543.             }
  544.         }
  545.     }
  546.     else if (c == 127) {
  547.         if (*curr_note->carat.text != '\0') {
  548.             remove_char_from_string(curr_note->carat.text);
  549.  
  550.             if (redraw) {
  551.                 carat_from_ptr(curr_note,PTRCHANGE_CLICK);
  552.                 note_refresh(curr_note);
  553.             }
  554.         }
  555.     }
  556.     else if (c == '\t') {
  557.         if (strlen(curr_note->text) < (STRLEN_NOTETEXT - 1)) {
  558.             add_char_to_string(curr_note->carat.text,' ');
  559.  
  560.             curr_note->carat.text++;
  561.  
  562.             if (redraw) {
  563.                 carat_from_ptr(curr_note,PTRCHANGE_CLICK);
  564.                 note_refresh(curr_note);
  565.             }
  566.         }
  567.     }
  568.     else if (c == '\r') {
  569.         carat_clear(curr_note);
  570.  
  571.         /* If commodities window open, refresh listview */
  572.  
  573.         if (commod) {
  574.             GT_SetGadgetAttrs(commodGadgets[commod_listview],
  575. commod,NULL,GTLV_Labels,~0,TAG_END);
  576.             GT_SetGadgetAttrs(commodGadgets[commod_listview],
  577. commod,NULL,GTLV_Labels,&prj->commodlist,TAG_END);
  578.         }
  579.     }
  580.     else {
  581.         if (strlen(curr_note->text) < (STRLEN_NOTETEXT - 1)) {
  582.             /* Add the character then refresh */
  583.  
  584.             add_char_to_string(curr_note->carat.text,c);
  585.  
  586.             curr_note->carat.text++;
  587.  
  588.             if (redraw) {
  589.                 carat_from_ptr(curr_note,PTRCHANGE_CLICK);
  590.                 note_refresh(curr_note);
  591.             }
  592.         }
  593.     }
  594. }
  595.