/* 
Copyright (c) 1991-2000 UserLand Software, Inc. 

Permission is hereby granted, free of charge, to any person obtaining a 
copy of this software and associated documentation files (the 
"Software"), to deal in the Software without restriction, including 
without limitation the rights to use, copy, modify, merge, publish, 
distribute, sublicense, and/or sell copies of the Software, and to 
permit persons to whom the Software is furnished to do so, subject to the 
following conditions: 

The above copyright notice and this permission notice shall be 
included in all copies or substantial portions of the Software. 

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
*/ 


#include "iowacore.h"
#include <applet.h>
#include <appletcolorpopup.h>
#include <appletmenuops.h>
#include "iowastatusbar.h"


#define idstylingpopup 141
#define backgroundcoloritem 1
#define fillcoloritem 3
#define textcoloritem 4
#define framecoloritem 5


#define drawinset 5 /*inset 5 pixels all around*/

#define colorpopupsize 8

#define popupwidth 75
#define popupheight 16

#define textheight 16
#define namewidth 60
#define scriptwidth 200

#define editfont kFontIDGeneva
#define editsize 9
#define editstyle 0
		


static tyobject globalobject; 
	



static void getpopupstring (bigstring bs) {
	
	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	MenuHandle hmenu;
	
	hmenu = GetMenu (idstylingpopup);
	
	if (hmenu == nil) {
		
		setstringlength (bs, 0);
		
		return;
		}
	
	GetMenuItemText (hmenu, (**he).stylingpopup.itemselected, bs);
	
	firstword (bs, ' ', bs);
	} /*getpopupstring*/
	
	
void invalstatusbar (void) {
	
	hdlappwindow ha = app.appwindow;
	Rect r = (**ha).statusrect;
	
	apppostcallback ();
	
	pushclip (r);
	
	iowainvalrect (&r);
	
	popclip ();
	
	appprecallback ();
	} /*invalstatusbar*/
	
	
static void statusbarsetrects (void) {
	
	/*
	this version puts the popup menu as the leftmost object in
	the status bar.
	*/

	hdlcard hc = iowadata;
	hdlappwindow ha = app.appwindow;
	boolean flcolorpopup = (**ha).flcolorwindow && colorenabled ();
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	Rect rstatus = (**ha).statusrect;
	Rect r, rcentered;
	
	/*set up the popup menu rect*/ {
	
		r.top = r.left = 0;
		
		r.bottom = popupheight;
		
		r.right = popupwidth;
		
		centerrect (&r, rstatus);
		
		r.right = rstatus.right - drawinset;
		
		r.left = r.right;
		
		if (flcolorpopup)
			r.left -= popupwidth;
		
		(**he).rpopup = r;
		}
		
	/*set up the rectangle for the color popup menu*/ {
		
		r.top = r.left = 0;
		
		r.bottom = colorpopupsize;
		
		r.right = colorpopupsize;
		
		centerrect (&r, rstatus); /*center it vertically*/
		
		r.right = (**he).rpopup.left - 2;
		
		r.left = r.right;
		
		if (flcolorpopup)
			r.left -= colorpopupsize;
		
		(**he).rcolorpopup = r;
		}

	/*set up the name editing rectangle*/ {
		
		r.top = r.left = 0;
		
		r.bottom = textheight;
		
		r.right = namewidth;
		
		centerrect (&r, rstatus);
		
		rcentered = r;
		
		r.left = rstatus.left + 3; /*matches inset of the palette, see apppalette.c*/
		
		r.right = r.left + namewidth;
		
		(**he).rname = r;
		}
	
	/*set up the script editing rectangle*/ {
		
		r.left = (**he).rname.right + drawinset + 4;
		
		r.right = (**he).rcolorpopup.left - (drawinset + 4);
		
		r.top = rcentered.top;
		
		r.bottom = rcentered.bottom;
		
		(**he).rscript = r;
		}
	} /*statusbarsetrects*/
	

static void otherstatusbarsetrects (void) {

	/*
	this version puts the script as the leftmost object in
	the status bar.
	*/

	hdlcard hc = iowadata;
	hdlappwindow ha = app.appwindow;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	Rect rstatus = (**ha).statusrect;
	Rect r, rcentered;
	
	/*set up the color popup menu*/ {
		
		r.top = r.left = 0;
		
		r.bottom = colorpopupsize;
		
		r.right = colorpopupsize;
		
		centerrect (&r, rstatus);
		
		r.left = rstatus.left + 3; /*matches inset of the palette, see apppalette.c*/
		
		r.right = r.left + colorpopupsize;
		
		r.bottom = r.top + colorpopupsize;
		
		(**he).rcolorpopup = r;
		}

	/*set up the popup menu rect*/ {
	
		r.top = r.left = 0;
		
		r.bottom = popupheight;
		
		r.right = popupwidth;
		
		centerrect (&r, rstatus);
		
		r.left = (**he).rcolorpopup.right + (colorpopupsize / 2);
		
		r.right = r.left + popupwidth;
		
		(**he).rpopup = r;
		}
		
	/*set up the name editing rectangle*/ {
		
		r.top = r.left = 0;
		
		r.bottom = textheight;
		
		r.right = namewidth;
		
		centerrect (&r, rstatus);
		
		rcentered = r;
		
		r.left = (**he).rpopup.right + (2 * drawinset); 
		
		r.right = r.left + namewidth;
		
		(**he).rname = r;
		}
	
	/*set up the script editing rectangle*/ {
		
		r.left = (**he).rname.right + drawinset;
		
		r.right = rstatus.right - drawinset;
		
		r.top = rcentered.top;
		
		r.bottom = rcentered.bottom;
		
		(**he).rscript = r;
		}
	} /*otherstatusbarsetrects*/
	

static void drawnameandscript (void) {

	/*
	draw the editable text linked into the current object
	*/ 
		
	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	boolean flupdatebuffer = false, flbitmap = false;
	hdlobject hobject;
	Rect r;
	
	getsingleselectedobject (&hobject); /*nil if not exactly one selected object*/
	
	if (hobject == nil)
		hobject = (**hc).activetextobject; /*1.0b11*/
		
	r = (**he).rname;
	
	flbitmap = iowaopenbitmap (r);
	
	pushcolors (&blackcolor, &whitecolor);
	
	pushstyle (editfont, editsize, editstyle);
	
	EraseRect (&r);
	
	FrameRect (&r);
	
	(**he).flnameempty = true;
		
	if (hobject != nil) {
	
		(**he).flnameempty = (**hobject).objectname == nil;
			
		if ((**he).flstatusbaredit && (**he).fleditname) 
			(**hc).updatethiseditbuffer = (Handle) (**he).heditbuffer;
		else 
			editdrawtexthandle ((**hobject).objectname, r, leftjustified);
		}
		
	popstyle ();
	
	popcolors ();

	if (flbitmap)
		iowaclosebitmap ();
	
	r = (**he).rscript;
	
	flbitmap = iowaopenbitmap (r);
	
	pushcolors (&blackcolor, &whitecolor);
	
	pushstyle (editfont, editsize, editstyle);
	
	EraseRect (&r);
	
	FrameRect (&r);
	
	(**he).flscriptempty = true;
		
	if (hobject != nil) {
		
		(**he).flscriptempty = (**hobject).objectscript == nil;
	
		if ((**he).flstatusbaredit && (!(**he).fleditname))
			(**hc).updatethiseditbuffer = (Handle) (**he).heditbuffer;
		else 
			editdrawtexthandle ((**hobject).objectscript, r, leftjustified);
		}
		
	popstyle ();
	
	popcolors ();

	if (flbitmap)
		iowaclosebitmap ();
	} /*drawnameandscript*/
	
	
void iowachecknameandscriptdisplay (void) {

	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	boolean fldraw = false;
	
	if ((!(**he).flnameempty) || (!(**he).flscriptempty))
		fldraw = true;
		
	else { /*both the name and script displays are currently empty*/
	
		hdlobject h;
		
		getsingleselectedobject (&h); 
		
		if (h != nil) { /*exactly one selected object*/
		
			fldraw = ((**h).objectname != nil) || ((**h).objectscript != nil);
			}
		}
	
	if (fldraw) {
	
		hdlappwindow ha = app.appwindow;
		Rect r = (**ha).statusrect;
		
		apppostcallback ();
		
		pushclip (r);
		
		(**hc).updatethiseditbuffer= nil;
		
		drawnameandscript ();
		
		editupdate ((hdleditrecord) (**hc).updatethiseditbuffer);
		
		popclip ();
		
		appprecallback ();
		}
	
	iowainvalrect (&(**he).rcolorpopup); /*force refresh*/
	} /*iowachecknameandscriptdisplay*/
	
		
static void getcolorpopupcolor (RGBColor *rgb) {

	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	short mode = (**he).stylingpopup.itemselected;
	hdlobject hobject;
	
	if (mode == backgroundcoloritem) {
	
		*rgb = (**hc).backcolor;
		
		return; /*doesn't depend on a single selected object*/
		}
	
	if (!getsingleselectedobject (&hobject)) {
	
		*rgb = whitecolor; 
		
		return;
		}
		
	switch (mode) {
		
		case fillcoloritem:
			*rgb = (**hobject).objectfillcolor; break;
			
		case textcoloritem:
			*rgb = (**hobject).objecttextcolor; break;
			
		case framecoloritem:
			*rgb = (**hobject).objectframecolor; break;
			
		} /*switch*/	
	} /*getcolorpopupcolor*/
	
		
boolean iowadrawstatusbar (void) {

	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	Rect rstatus = (**app.appwindow).statusrect;
	boolean flbitmap;
	
	flbitmap = iowaopenbitmap (rstatus);
	
	statusbarsetrects (); /*set up rpopup, rname, rscript fields of (**he)*/
	
	pushbackcolor (&lightbluecolor);
	
	EraseRect (&rstatus);
				
	/*draw the styling popup*/ {
	
		typopuprecord popup = (**he).stylingpopup;
		
		popup.popuprect = (**he).rpopup;
		
		getpopupstring (popup.bs);
		
		drawpopup (&popup);
		
		(**he).stylingpopup = popup;
		}
	
	/*draw the color popup*/ {
		
		RGBColor rgb;
		Rect r;
		
		getcolorpopupcolor (&rgb);
		
		pushbackcolor (&rgb); 
		
		r = (**he).rcolorpopup;
		
		EraseRect (&r);
		
		popbackcolor ();
		
		pushforecolor (&blackcolor);
		
		FrameRect (&r);
		
		popforecolor ();
		}
		
	popbackcolor ();
	
	(**hc).updatethiseditbuffer = nil;
	
	drawnameandscript ();
	
	if (flbitmap)
		iowaclosebitmap ();
		
	editupdate ((hdleditrecord) (**hc).updatethiseditbuffer);
	
	return (true);
	} /*iowadrawstatusbar*/
	
	
static boolean stylinggetmenu (void) {
	
	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	MenuHandle hmenu;
	
	(**he).stylingpopup.hmenu = hmenu = GetMenu (idstylingpopup);
	
	(**he).stylingpopup.idmenu = idstylingpopup;
	
	(**he).stylingpopup.checkeditem = (**he).stylingpopup.itemselected;
	
	(**he).stylingpopup.fldisposemenu = false; /*menu was loaded from resource, don't dispose it*/
	
	if (colorenabled ()) 
		enableallmenuitems (hmenu);
	else
		disableallmenuitems (hmenu);
		
	if ((**hc).selectionlist == nil) {
	
		disableallmenuitems (hmenu);
		
		enablemenuitem (hmenu, backgroundcoloritem);
		}
		
	return (true);
	} /*stylinggetmenu*/
	
	
static boolean stylingmenuselect (void) {
			
	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	
	iowainvalrect (&(**he).rcolorpopup); /*force refresh*/

	return (true);
	} /*stylingmenuselect*/
	
	
static boolean getselectionstyling (tyobject *obj) {
	
	hdlcard hc = iowadata;
	hdlobject h = (**hc).selectionlist;
	
	if (h == nil)
		return (false);
		
	*obj = **h;
	
	return (true);
	} /*getselectionstyling*/
	
	
static boolean settextcolorvisit (hdlobject h) {
	
	(**h).objecttextcolor = globalobject.objecttextcolor;

	(**h).objectinval = true;
	
	return (true);
	} /*settextcolorvisit*/
	
	
static void settextcolor (RGBColor *rgb) {

	hdlcard hc = iowadata;
	
	(**hc).defaults.objecttextcolor = *rgb;
	
	globalobject.objecttextcolor = *rgb;

	flatvisitselectedobjects (&settextcolorvisit);
	} /*settextcolor*/
	

static boolean setframecolorvisit (hdlobject h) {
	
	(**h).objectframecolor = globalobject.objectframecolor;

	(**h).objectinval = true;
	
	return (true);
	} /*setframecolorvisit*/
	
	
static void setframecolor (RGBColor *rgb) {

	hdlcard hc = iowadata;
	
	(**hc).defaults.objectframecolor = *rgb;
	
	globalobject.objectframecolor = *rgb;

	flatvisitselectedobjects (&setframecolorvisit);
	} /*setframecolor*/
	

static boolean setfillcolorvisit (hdlobject h) {
	
	(**h).objectfillcolor = globalobject.objectfillcolor;

	(**h).objectinval = true;
	
	return (true);
	} /*setfillcolorvisit*/
	
	
static void setfillcolor (RGBColor *rgb) {

	hdlcard hc = iowadata;
	
	(**hc).defaults.objectfillcolor = *rgb;
	
	globalobject.objectfillcolor = *rgb;

	flatvisitselectedobjects (&setfillcolorvisit);
	} /*setfillcolor*/
	

static boolean setdropshadowdepthvisit (hdlobject h) {
	
	(**h).objectdropshadowdepth = globalobject.objectdropshadowdepth;
	
	(**h).objectinval = true;
	
	return (true);
	} /*setdropshadowdepthvisit*/
	
	
static void setdropshadowdepth (short depth) {

	hdlcard hc = iowadata;
	
	(**hc).defaults.objectdropshadowdepth = depth;
	
	globalobject.objectdropshadowdepth = depth;

	flatvisitselectedobjects (&setdropshadowdepthvisit);
	} /*setdropshadowdepth*/
	

static boolean setlinespacingvisit (hdlobject h) {
	
	(**h).objectlinespacing = globalobject.objectlinespacing;

	(**h).objectinval = true;

	return (true);
	} /*setlinespacingvisit*/
	
	
static void setlinespacing (short spacing) {

	hdlcard hc = iowadata;
	
	(**hc).defaults.objectlinespacing = spacing;
	
	globalobject.objectlinespacing = spacing;

	flatvisitselectedobjects (&setlinespacingvisit);
	} /*setlinespacing*/
	

static boolean setindentationvisit (hdlobject h) {
	
	(**h).objectindentation = globalobject.objectindentation;

	(**h).objectinval = true;
	
	return (true);
	} /*setindentationvisit*/
	
	
static void setindentation (short indent) {

	hdlcard hc = iowadata;
	
	(**hc).defaults.objectindentation = indent;
	
	globalobject.objectindentation = indent;

	flatvisitselectedobjects (&setindentationvisit);
	} /*setindentation*/
	

static boolean setcolor (RGBColor *rgb) {

	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	
	switch ((**he).stylingpopup.itemselected) {
		
		case backgroundcoloritem:
			(**hc).backcolor = *rgb;
			
			iowainvalrect (&(**app.appwindow).contentrect);
			
			break;
			
		case fillcoloritem:
			setfillcolor (rgb);
			
			break;
			
		case textcoloritem:
			settextcolor (rgb);
			
			break;
			
		case framecoloritem:
			setframecolor (rgb);
			
			break;
		} /*switch*/
		
	iowainvalrect (&(**he).rcolorpopup); /*force refresh*/
	
	return (true);
	} /*setcolor*/
	
		
void iowainitstatusbar (void) {
	
	/*
	called when a new iowa window is allocated.
	*/
	
	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	typopuprecord popup;
	
	initpopuprecord (&popup);
	
	popup.getmenucallback = &stylinggetmenu;
	
	popup.menuselectcallback = &stylingmenuselect;
	
	popup.itemselected = backgroundcoloritem;
	
	(**he).stylingpopup = popup;
	} /*iowainitstatusbar*/
	
	
boolean iowacursorinstatusbar (void) {

	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	Point pt = mousestatus.localpt;
	
	if (adjustpopupcursor (&(**he).stylingpopup))
		return (true);
	
	if (PtInRect (pt, &(**he).rcolorpopup)) {
		
		setcursortype (cursorispopup);
		
		return (true);
		}
	
	if (PtInRect (pt, &(**he).rname)) {
		
		setcursortype (cursorisibeam);
		
		return (true);
		}
	
	if (PtInRect (pt, &(**he).rscript)) {
		
		setcursortype (cursorisibeam);
		
		return (true);
		}
	
	if ((**he).flstatusbaredit && (**hc).flactive) {
	
		apppostcallback ();
		
		pushclip ((**app.appwindow).statusrect);
		
		editidle ((**he).heditbuffer);
		
		popclip ();
		
		appprecallback ();
		}
		
	return (false);
	} /*iowacursorinstatusbar*/
	
	
void iowaactivatestatusbar (boolean flactive) {
	
	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	
	if ((**he).flstatusbaredit) {
	
		apppostcallback ();
		
		pushclip ((**app.appwindow).statusrect);
		
		editactivate ((**he).heditbuffer, flactive);
		
		popclip ();
		
		appprecallback ();
		}
		
	invalstatusbar ();
	} /*iowaactivatestatusbar*/
	
	
static void justclick (void) {

	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	
	apppostcallback ();

	pushclip ((**app.appwindow).statusrect);

	editclickbottleneck (mousestatus.localpt, keyboardstatus.flshiftkey, (**he).heditbuffer);

	popclip ();

	appprecallback ();		
	} /*justclick*/


static boolean mouseinstatusbareditor (boolean fleditname, hdlobject hobject) {
	
	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	Rect r;
	Handle htext;
	hdleditrecord hedit;
	boolean fl;
	
	if ((**he).flstatusbaredit) { /*already editing*/
		
		if (fleditname == (**he).fleditname) { /*still editing the same field*/
			
			justclick ();
			
			return (true);
			}
		else
			closestatusbareditor (); /*we're about to switch to editing the other field*/
		}
	
	if (fleditname) {
		
		r = (**he).rname;
		
		htext = (**hobject).objectname;
		}
	else {
		
		r = (**he).rscript;
		
		htext = (**hobject).objectscript;
		}
	
	pushstyle (editfont, editsize, editstyle);
			
	fl = editnewbufferfromhandle (r, false, htext, &hedit);
	
	popstyle ();
	
	if (!fl)
		return (false);
	
	(**he).flstatusbaredit = true;
	
	(**he).fleditname = fleditname;
	
	(**he).hobjectinstatusbar = hobject;
	
	(**he).redit = r;
	
	(**he).heditbuffer = hedit;
	
	justclick ();
	
	return (true);
	} /*mouseinstatusbareditor*/
	
	
boolean statusbareditor (boolean fleditname, hdlobject hobject) {
	
	/*
	special entry point for external callers.
	*/
	
	boolean fl;
	
	apppostcallback ();
	
	fl = mouseinstatusbareditor (fleditname, hobject);
	
	appprecallback ();
	
	return (fl);
	} /*statusbareditor*/
	
	
boolean statusbarkeystroke (void) {
	
	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	char ch = keyboardstatus.chkb;
	
	if (!(**he).flstatusbaredit) /*we don't consume the keystroke*/
		return (false);
	
	if (ch == chtab) {
		
		mouseinstatusbareditor (!(**he).fleditname, (**he).hobjectinstatusbar);
		
		return (true); /*we consume the keystroke*/
		}
	
	if ((ch == chreturn) || (ch == chenter)) {
		
		closestatusbareditor ();
		
		return (true); /*we consume the keystroke*/
		}
		
	apppostcallback ();
	
	pushclip ((**app.appwindow).statusrect);
	
	editkeystroke (ch, (**he).heditbuffer);
	
	popclip ();
	
	appprecallback ();
	
	if ((**he).fleditname)
		(**he).flnameempty = false;
	else
		(**he).flscriptempty = false;
	
	return (true); /*we consume the keystroke*/
	} /*statusbarkeystroke*/
	
	
boolean closestatusbareditor (void) {
	
	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	hdleditrecord hedit = (**he).heditbuffer;
	hdlobject hobject = (**he).hobjectinstatusbar;
	Handle htext;
	
	if (!(**he).flstatusbaredit)
		return (true);
		
	if (!editgettexthandlecopy (hedit, &htext)) /*htext is nil if there is no text*/
		return (false);
		
	apppostcallback ();
	
	pushclip ((**app.appwindow).statusrect);
	
	editdispose (hedit);
	
	popclip ();
	
	appprecallback ();
	
	if ((**he).fleditname) 
		setobjectname (hobject, htext);
	else 
		setobjectscript (hobject, htext);
	
	(**he).flstatusbaredit = false;
	
	(**he).hobjectinstatusbar = nil;
	
	(**he).heditbuffer = nil;
	
	madechanges ();
	
	return (true);
	} /*closestatusbareditor*/
	
	
boolean iowamouseinstatus (void) {
	
	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	Point pt = mousestatus.localpt;
	hdlobject hobject;
	
	if (PtInRect (pt, &(**he).rcolorpopup)) {
		
		RGBColor rgb;
		
		if (clickcolorpopup (pt, &rgb))
			setcolor (&rgb);
		}
		
	if (popupclick (&(**he).stylingpopup))
		return (true);
	
	if (!getsingleselectedobject (&hobject)) {
	
		hobject = (**hc).activetextobject;
		
		if (hobject == nil) /*nothing is selected or being edited*/
			return (false);
		
		apppostcallback ();
	
		enterarrowmode (); /*automatically switch to object mode*/
		
		(**hobject).objectinval = true;
		
		appprecallback ();
		}
		
	if (PtInRect (pt, &(**he).rname)) {
		
		mouseinstatusbareditor (true, hobject);
		
		return (true);
		}
	
	if (PtInRect (pt, &(**he).rscript)) {
		
		mouseinstatusbareditor (false, hobject);
		
		return (true);
		}

	return (false);
	} /*iowamouseinstatus*/