//	Zinc Application Framework - Z_BUTTON.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

#include <z_button.hpp>
#include <z_string.hpp>
#include <z_ctype.hpp>
#include <z_app.hpp>
#include <z_utils.hpp>
#define ZAF_BUTTON_INFO
#include "img_def.cpp"
#include "gbl_def.cpp"

// ----- ZafButton ----------------------------------------------------------

ZafButton::ZafButton(int left, int top, int width, int height,
	const ZafIChar *text, ZafBitmapData *zBitmapData,
	ZafButtonType tButtonType) :
	ZafWindowObject(left, top, width, height),
	value(0), sendMessageText(ZAF_NULLP(ZafIChar)),
	stringData(ZAF_NULLP(ZafStringData)),
	bitmapData(ZAF_NULLP(ZafBitmapData)), depth(2),
	// attributes
	allowDefault(false), allowToggling(false), autoRepeatSelection(false),
	autoSize(true),	buttonType(tButtonType), depressed(false),
	hotKeyChar(0), hotKeyIndex(-1), selectOnDoubleClick(false),
	selectOnDownClick(false), sendMessageWhenSelected(false),
	hzJustify(ZAF_HZ_CENTER), vtJustify(ZAF_VT_CENTER)
{
	saveRegion = zafRegion;

#if defined(ZAF_TEXT_MODE)
    depth = 0;
#endif

	// Check the image information.
	ImageAllocate();

	// Set the button data.
	if (buttonType == ZAF_FLAT_BUTTON)
		depth = 0;
	if (zBitmapData)
		SetBitmapData(zBitmapData);
	if (text)
		SetStringData(new ZafStringData(text));
}

ZafButton::ZafButton(int left, int top, int width, int height,
	ZafStringData *zStringData, ZafBitmapData *zBitmapData,
	ZafButtonType tButtonType) :
	ZafWindowObject(left, top, width, height),
	value(0), sendMessageText(ZAF_NULLP(ZafIChar)),
	stringData(ZAF_NULLP(ZafStringData)),
	bitmapData(ZAF_NULLP(ZafBitmapData)), depth(2),
	// attributes
	allowDefault(false), allowToggling(false), autoRepeatSelection(false),
	autoSize(true), buttonType(tButtonType), depressed(false),
	hotKeyChar(0), hotKeyIndex(-1), selectOnDoubleClick(false),
	selectOnDownClick(false), sendMessageWhenSelected(false),
	hzJustify(ZAF_HZ_CENTER), vtJustify(ZAF_VT_CENTER)
{
	saveRegion = zafRegion;

#if defined(ZAF_TEXT_MODE)
    depth = 0;
#endif

	// Check the image information.
	ImageAllocate();

	// Set the button data.
	if (buttonType == ZAF_FLAT_BUTTON)
		depth = 0;
	if (zBitmapData)
		SetBitmapData(zBitmapData);
	if (zStringData)
		SetStringData(zStringData);
}

ZafButton::ZafButton(const ZafButton &copy) :
	ZafWindowObject(copy),
	value(copy.value), stringData(ZAF_NULLP(ZafStringData)),
	bitmapData(ZAF_NULLP(ZafBitmapData)), depth(copy.depth),
	// attributes
	allowDefault(copy.allowDefault), allowToggling(copy.allowToggling),
	autoRepeatSelection(copy.autoRepeatSelection), autoSize(copy.autoSize),
	buttonType(copy.buttonType), depressed(false),
	hotKeyChar(copy.hotKeyChar), hotKeyIndex(copy.hotKeyIndex),
	selectOnDoubleClick(copy.selectOnDoubleClick),
	selectOnDownClick(copy.selectOnDownClick),
	sendMessageWhenSelected(copy.sendMessageWhenSelected),
	hzJustify(copy.hzJustify), vtJustify(copy.vtJustify),
	saveRegion(copy.saveRegion)
{
	// Check the image information.
	ImageAllocate();

	// Initialize the bitmap information.
	if (copy.bitmapData)
	{
		if (copy.bitmapData->Destroyable())
			SetBitmapData(new ZafBitmapData(*copy.bitmapData));
		else 
			SetBitmapData(copy.bitmapData);
	}

	// Initialize the string information.
	if (copy.stringData)
	{
		if (copy.stringData->Destroyable())
			SetStringData(new ZafStringData(*copy.stringData));
		else 
			SetStringData(copy.stringData);
	}

	// Initialize the send message text.
	sendMessageText = copy.sendMessageText ? strdup(copy.sendMessageText) : ZAF_NULLP(ZafIChar);

	// Determine the user function.
	if (SendMessageWhenSelected())
		memberUserFunction = (MemberUserFunction)&ZafButton::SendMessage;
}

ZafButton::~ZafButton(void)
{
	// Remove the data notification.
	if (bitmapData)
		bitmapData->SubtractNotification(this, (ZafUpdateFunction)UpdateBitmap);
	if (stringData)
		stringData->SubtractNotification(this, (ZafUpdateFunction)UpdateString);

	// Check the image information.
	ImageFree();

	// Restore the button information.
	if (bitmapData && bitmapData->Destroyable() && bitmapData->NotifyCount() == 0)
		delete bitmapData;

	// Restore the string information.
	if (stringData && stringData->Destroyable() && stringData->NotifyCount() == 0)
		delete stringData;

	if (sendMessageText)
		delete []sendMessageText;
}

void ZafButton::ClearImage(void)
{
	// Make sure the request is valid.
	if (!bitmapData)
		return;

	// On Motif, the radio-button and check-box are embedded in the
	// bitmapData.  The user cannot delete the data in these cases.
#	if defined(ZAF_MOTIF) || defined(ZAF_INDEPENDENT)
	if (ButtonType() == ZAF_RADIO_BUTTON || ButtonType() == ZAF_CHECK_BOX)
		return;
#	endif

	// Clear the image.
	SetBitmapData(ZAF_NULLP(ZafBitmapData));
}

void ZafButton::ClearText(void)
{
	// Make sure the request is valid.
	if (!stringData)
		return;

	// Clear the text.
	if (stringData && stringData->Destroyable() && stringData->NotifyCount() == 0)
		delete stringData;
	stringData = ZAF_NULLP(ZafStringData);

	// Redisplay the data.
	if (screenID)
		RedisplayData();
}

ZafRegionStruct ZafButton::ComputeDrawRegions(ZafRegionStruct &drawRegion,
	ZafRegionStruct &imageRegion, ZafRegionStruct &textRegion, int margin)
{
	// Computes drawing regions for the image and text of a button
	// based on the justification attributes and the regions pased in.
	// All the parameters are assumed to use the same coordinate type, and
	// the return region has the same coordinate type.
	// * "drawRegion" specifies the region inside of which the image and
	//   text are to be drawn. If the width and/or height of drawRegion is
	//   zero, then drawRegion is modified to the smallest size needed to
	//   properly contain the image and the text.
	// * "imageRegion" contains the size of the image on input and
	//   the region for drawing the image on return.
	// * "textRegion" contains the size of the text on input and
	//   the region for drawing the text on return.
	// * "margin" is the space between the image and the text.
	// * The returned region specifies the size of the smallest region needed
	//   to encompass the image and text.

	// Create local variables to optimize code.
	int imageWidth = imageRegion.Width();
	int imageHeight = imageRegion.Height();
	int textWidth = textRegion.Width();
	int textHeight = textRegion.Height();

	// If there is no image or no text, then margin should be ignored.
	if (imageWidth == 0 || textWidth == 0)
		margin = 0;

	// Compute the minimum width and height needed to draw the image and text.
	int minimumWidth;
	int minimumHeight;
	if (hzJustify == ZAF_HZ_CENTER)
	{
		minimumHeight = imageHeight + textHeight + margin;
		minimumWidth = ZafMax(imageWidth, textWidth);
	}
	else
	{
		minimumHeight = ZafMax(imageHeight, textHeight);
		minimumWidth = imageWidth + textWidth + margin;
	}

	// Modify drawRegion if specified.
	if (drawRegion.Width() == 0)
		drawRegion.right = drawRegion.left + minimumWidth - 1;
	if (drawRegion.Height() == 0)
		drawRegion.bottom = drawRegion.top + minimumHeight - 1;

	// "xDelta" and "yDelta" are used to justify the image and text
	// as a unit within drawRegion.
	int yDelta;
	int xDelta;
	if (vtJustify == ZAF_VT_TOP)
		yDelta = 0;
	else if (vtJustify == ZAF_VT_BOTTOM)
		yDelta = drawRegion.Height() - minimumHeight;
	else
		yDelta = (drawRegion.Height() - minimumHeight) / 2;

	// Compute the regions.
	if (hzJustify == ZAF_HZ_CENTER)
	{
		xDelta = (drawRegion.Width() - minimumWidth) / 2;
		imageRegion.left = drawRegion.left + (minimumWidth - imageWidth) / 2 + xDelta;
		textRegion.left = drawRegion.left + (minimumWidth - textWidth) / 2 + xDelta;
		if (vtJustify == ZAF_VT_BOTTOM)
		{
			textRegion.top = drawRegion.top + yDelta;
			imageRegion.top = drawRegion.top + textHeight + margin + yDelta;
		}
		else
		{
			imageRegion.top = drawRegion.top + yDelta;
			textRegion.top = drawRegion.top + imageHeight + margin + yDelta;
		}
	}
	else
	{
		imageRegion.top = drawRegion.top + (minimumHeight - imageHeight) / 2 + yDelta;
		textRegion.top = drawRegion.top + (minimumHeight - textHeight) / 2 + yDelta;
		if (hzJustify == ZAF_HZ_LEFT)
		{
			imageRegion.left = drawRegion.left;
			textRegion.left = drawRegion.left + imageWidth + margin;
		}
		else if (hzJustify == ZAF_HZ_RIGHT)
		{
			xDelta = drawRegion.Width() - minimumWidth;
			textRegion.left = drawRegion.left + xDelta;
			imageRegion.left = drawRegion.left + textWidth + margin + xDelta;
		}
	}
	imageRegion.right = imageRegion.left + imageWidth - 1;
	imageRegion.bottom = imageRegion.top + imageHeight - 1;
	textRegion.right = textRegion.left + textWidth - 1;
	textRegion.bottom = textRegion.top + textHeight - 1;

	// Return the minimum region needed to draw the image and text together.
	ZafRegionStruct sizeRegion;
	sizeRegion.coordinateType = drawRegion.coordinateType;
	sizeRegion.left = 1;
	sizeRegion.top = 1;
	sizeRegion.right = minimumWidth;
	sizeRegion.bottom = minimumHeight;
	return (sizeRegion);
}

void ZafButton::ConvertCoordinates(ZafCoordinateType newCoordinateType)
{
	ConvertRegion(saveRegion, newCoordinateType);
	ZafWindowObject::ConvertCoordinates(newCoordinateType);
}

ZafEventType ZafButton::DragDropEvent(const ZafEventStruct &event)
{
	// Switch on the event type.
	ZafEventType ccode = event.type;
	switch (ccode)
	{
	case S_DROP_DEFAULT:
		// ZafButton treats S_DROP_MOVE as S_DROP_COPY.
		if (windowManager->dragObject->MoveDraggable())
			ccode = S_DROP_MOVE;
		else if (windowManager->dragObject->CopyDraggable())
			ccode = S_DROP_COPY;
		else
		{
			ccode = S_ERROR;
			break;
		}

	case S_DROP_MOVE:
	case S_DROP_COPY:
		if (!Disabled() && AcceptDrop() && windowManager->dragObject != this)
		{
			ZafButton *dragButton = DynamicPtrCast(windowManager->dragObject, ZafButton);
			if (dragButton)
			{
				if (dragButton->bitmapData && dragButton->bitmapData != bitmapData &&
					ButtonType() != ZAF_RADIO_BUTTON && dragButton->ButtonType() != ZAF_RADIO_BUTTON &&
					ButtonType() != ZAF_CHECK_BOX && dragButton->ButtonType() != ZAF_CHECK_BOX)
					SetBitmapData(dragButton->bitmapData);
				if (dragButton->Text() != Text())
					SetText(dragButton->Text());
			}
			else
				ccode = ZafWindowObject::DragDropEvent(event);
		}
		else
			ccode = S_ERROR;
		break;

	default:
		ccode = ZafWindowObject::DragDropEvent(event);
		break;
	}

	// Return the control code.
	return (ccode);
}

ZafWindowObject *ZafButton::Duplicate(void)
{
	return (new ZafButton(*this));
}

#if defined(ZAF_TEXT_MODE)
void ZafButton::ImageAllocate(void) {}
void ZafButton::ImageFree(bool) {}
#else
void ZafButton::ImageAllocate(void)
{
	// Initialize the images.
	if (!checkBitmap)
	{
		ZafI18nData::AddStaticModule(ImageFree);
		checkBitmap = new ZafBitmapData(_check_ZafBitmap);
		checkBitmap->staticHandle = true;
		checkBitmap->SetDestroyable(false);

		checkSelectedBitmap = new ZafBitmapData(_checkSelected_ZafBitmap);
		checkSelectedBitmap->staticHandle = true;
		checkSelectedBitmap->SetDestroyable(false);

		radioBitmap = new ZafBitmapData(_radio_ZafBitmap);
		radioBitmap->staticHandle = true;
		radioBitmap->SetDestroyable(false);

		radioSelectedBitmap = new ZafBitmapData(_radioSelected_ZafBitmap);
		radioSelectedBitmap->staticHandle = true;
		radioSelectedBitmap->SetDestroyable(false);

#if defined(ZAF_MSWINDOWS)
		checkDepressedBitmap = new ZafBitmapData(_checkDepressed_ZafBitmap);
		checkDepressedBitmap->staticHandle = true;
		checkDepressedBitmap->SetDestroyable(false);

		checkSelectedDepressedBitmap = new ZafBitmapData(_checkSelectedDepressed_ZafBitmap);
		checkSelectedDepressedBitmap->staticHandle = true;
		checkSelectedDepressedBitmap->SetDestroyable(false);

		radioDepressedBitmap = new ZafBitmapData(_radioDepressed_ZafBitmap);
		radioDepressedBitmap->staticHandle = true;
		radioDepressedBitmap->SetDestroyable(false);

		radioSelectedDepressedBitmap = new ZafBitmapData(_radioSelectedDepressed_ZafBitmap);
		radioSelectedDepressedBitmap->staticHandle = true;
		radioSelectedDepressedBitmap->SetDestroyable(false);
#endif
	}
}

void ZafButton::ImageFree(bool globalRequest)
{
	// Destroy the static images.
	if (globalRequest && checkBitmap)
	{
		checkBitmap->staticHandle = false;
		delete checkBitmap;
		checkBitmap = ZAF_NULLP(ZafBitmapData);
		checkSelectedBitmap->staticHandle = false;
		delete checkSelectedBitmap;
		checkSelectedBitmap = ZAF_NULLP(ZafBitmapData);
		radioBitmap->staticHandle = false;
		delete radioBitmap;
		radioBitmap = ZAF_NULLP(ZafBitmapData);
		radioSelectedBitmap->staticHandle = false;
		delete radioSelectedBitmap;
		radioSelectedBitmap = ZAF_NULLP(ZafBitmapData);
#if defined(ZAF_MSWINDOWS)
		checkDepressedBitmap->staticHandle = false;
		delete checkDepressedBitmap;
		checkSelectedDepressedBitmap->staticHandle = false;
		delete checkSelectedDepressedBitmap;
		radioDepressedBitmap->staticHandle = false;
		delete radioDepressedBitmap;
		radioSelectedDepressedBitmap->staticHandle = false;
		delete radioSelectedDepressedBitmap;
#endif
	}
}
#endif

bool ZafButton::IsA(ZafClassID compareID) const
{
	bool retVal = (compareID == classID);
	if (!retVal)
	{
		if (ButtonType() == ZAF_CHECK_BOX)
			retVal = (compareID == ID_ZAF_CHECK_BOX);
		else if (ButtonType() == ZAF_RADIO_BUTTON)
			retVal = (compareID == ID_ZAF_RADIO_BUTTON);
	}
	return (retVal ? true : ZafWindowObject::IsA(compareID));
}

bool ZafButton::IsA(ZafClassName compareName) const
{
	return (!strcmp(compareName, className) ? true : ZafWindowObject::IsA(compareName));
}

ZafLogicalEvent ZafButton::LogicalEvent(const ZafEventStruct &event)
{
	ZafLogicalEvent ccode = MapEvent(defaultEventMap, event);
	return ((ccode == L_NONE) ? ZafWindowObject::LogicalEvent(event) : ccode);
}

const ZafPaletteStruct *ZafButton::MapClassPalette(ZafPaletteType type, ZafPaletteState state)
{
	const ZafPaletteStruct *palette = MapPalette(defaultPaletteMap, type, state);
	return (palette ? palette : ZafWindowObject::MapClassPalette(type, state));
}

ZafRegionStruct ZafButton::Region(void) const
{
	return (saveRegion);
}

ZafEventType ZafButton::SendMessage(const ZafEventStruct &event, ZafEventType ccode)
{
	// Call the base user function.
	ZafEventType errorCode = DefaultUserFunction(event, ccode);

	// Send the user message.
	if (ccode == L_DOUBLE_CLICK || (ccode == L_SELECT && !SelectOnDoubleClick()))
	{
		ZafEventStruct messageEvent(value);
		if (sendMessageText)
			messageEvent.text = strdup(sendMessageText);
		messageEvent.windowObject = this;
		eventManager->Put(messageEvent);
	}
	return (errorCode);
}

bool ZafButton::SetAllowDefault(bool setAllowDefault)
{
	// Make sure the attribute has changed.
	if (allowDefault != setAllowDefault && !screenID)
		allowDefault = setAllowDefault;

	// Return the current attribute.
	return (allowDefault);
}

bool ZafButton::SetAllowToggling(bool setAllowToggling)
{
	// Make sure the attribute has changed.
	if (allowToggling != setAllowToggling && !screenID)
		allowToggling = setAllowToggling;

	// Return the current attribute.
	return (allowToggling);
}

bool ZafButton::SetAutoRepeatSelection(bool setAutoRepeatSelection)
{
	// Make sure the attribute has changed.
	if (autoRepeatSelection != setAutoRepeatSelection && !screenID)
		autoRepeatSelection = setAutoRepeatSelection;

	// Return the current attribute.
	return (autoRepeatSelection);
}

bool ZafButton::SetAutoSize(bool setAutoSize)
{
	// Make sure the attribute has changed.
//	if (autoSize != setAutoSize && !screenID)
	if (!screenID)
		autoSize = setAutoSize;

	// Return the current attribute.
	return (autoSize);
}

ZafError ZafButton::SetBitmapData(ZafBitmapData *tBitmapData)
{
	// Remove the data notification.
	if (bitmapData)
		bitmapData->SubtractNotification(this, (ZafUpdateFunction)UpdateBitmap);

	// Reset the bitmap data.
	if (bitmapData && bitmapData != tBitmapData &&
		bitmapData->Destroyable() && bitmapData->NotifyCount() == 0)
		delete bitmapData;
	bitmapData = tBitmapData;

	// Add the data notification.
	if (bitmapData)
		bitmapData->AddNotification(this, (ZafUpdateFunction)UpdateBitmap);

	// Update the display.
	if (screenID)
		OSSetImage();

	return (ZAF_ERROR_NONE);
}

ZafButtonType ZafButton::SetButtonType(ZafButtonType newButtonType)
{
	// Make sure the attribute has changed.
	if (buttonType != newButtonType && !screenID)
	{
		// Change the button type.
		buttonType = newButtonType;
		depth = (buttonType == ZAF_3D_BUTTON || buttonType == ZAF_NATIVE_BUTTON) ? 2 : 0;
	}

	// Return the current attribute.
	return (buttonType);
}

ZafCoordinateType ZafButton::SetCoordinateType(ZafCoordinateType newCoordinateType)
{
	if (!screenID)
		saveRegion.coordinateType = ZafWindowObject::SetCoordinateType(newCoordinateType);

	// Return the current attribute.
	return (coordinateType);
}

int ZafButton::SetDepth(int setDepth)
{
	// Make sure the attribute has changed.
	if (depth != setDepth && !screenID)
		depth = setDepth;

	// Return the current attribute.
	return depth;
}

bool ZafButton::SetParentPalette(bool setParentPalette)
{
#if defined(ZAF_MSWINDOWS)
	if (buttonType == ZAF_3D_BUTTON || buttonType == ZAF_NATIVE_BUTTON)
	{
		parentPalette = false;
		return (parentPalette);
	}
#endif

	return (ZafWindowObject::SetParentPalette(setParentPalette));
}

ZafIChar ZafButton::SetHotKey(ZafIChar setHotKeyChar, int setHotKeyIndex)
{
	// hotKeyChar affects only the action (keyStroke), and keyKeyIndex
	// affects only the appearance (underline).
	if (hotKeyChar != setHotKeyChar)
		hotKeyChar = ToUpper(setHotKeyChar);
	if (hotKeyIndex != setHotKeyIndex)
		hotKeyIndex = setHotKeyIndex;

	// Return the current hot key.
	return (hotKeyChar);
}

ZafHzJustify ZafButton::SetHzJustify(ZafHzJustify setHzJustify)
{
	// Make sure the request is valid.
	if (hzJustify != setHzJustify && !screenID)
		hzJustify = setHzJustify;

	// Return the current attribute.
	return (hzJustify);
}

void ZafButton::SetRegion(const ZafRegionStruct &region)
{
	zafRegion = saveRegion = region;
}

bool ZafButton::SetSelectOnDoubleClick(bool setSelectOnDoubleClick)
{
	// Make sure the attribute has changed.
	if (selectOnDoubleClick != setSelectOnDoubleClick && !screenID)
		selectOnDoubleClick = setSelectOnDoubleClick;

	// Return the current attribute.
	return (selectOnDoubleClick);
}

bool ZafButton::SetSelectOnDownClick(bool setSelectOnDownClick)
{
	// Make sure the attribute has changed.
	if (selectOnDownClick != setSelectOnDownClick && !screenID)
		selectOnDownClick = setSelectOnDownClick;

	// Return the current attribute.
	return (selectOnDownClick);
}

const ZafIChar *ZafButton::SetSendMessageText(const ZafIChar *newSendMessageText)
{
	// Delete old text.
	if (sendMessageText)
		delete []sendMessageText;

	// Set the new text.
	sendMessageText = newSendMessageText ? strdup(newSendMessageText) : ZAF_NULLP(ZafIChar);

	// Return the current attribute.
	return (sendMessageText);
}

bool ZafButton::SetSendMessageWhenSelected(bool setSendMessageWhenSelected)
{
	// Make sure the attribute has changed.
	if (sendMessageWhenSelected != setSendMessageWhenSelected)
	{
		sendMessageWhenSelected = setSendMessageWhenSelected;
		if (sendMessageWhenSelected)
			memberUserFunction = (MemberUserFunction)&ZafButton::SendMessage;
		else
			memberUserFunction = (MemberUserFunction)&ZafWindowObject::DefaultUserFunction;
	}

	// Return the current attribute.
	return (sendMessageWhenSelected);
}

ZafError ZafButton::SetStringData(ZafStringData *tStringData)
{
	// Remove the data notification.
	if (stringData)
		stringData->SubtractNotification(this, (ZafUpdateFunction)UpdateString);

	// Reset the string data.
	if (stringData && stringData != tStringData &&
		stringData->Destroyable() && stringData->NotifyCount() == 0)
		delete stringData;
	stringData = tStringData;

	// Add the data notification.
	if (stringData)
		stringData->AddNotification(this, (ZafUpdateFunction)UpdateString);
	return (ZAF_ERROR_NONE);
}

ZafError ZafButton::SetText(const ZafIChar *text)
{
	// Reset the button text.
	if (stringData)
		stringData->SetText(text);
	else
		SetStringData(new ZafStringData(text));

	return (ZAF_ERROR_NONE);
}

ZafEventType ZafButton::SetValue(ZafEventType newValue)
{
	// Change the button value.
	value = newValue;
	return (value);
}

ZafVtJustify ZafButton::SetVtJustify(ZafVtJustify setVtJustify)
{
	// Make sure the request is valid.
	if (vtJustify != setVtJustify && !screenID)
		vtJustify = setVtJustify;

	// Return the current attribute.
	return (vtJustify);
}

ZafStringData *ZafButton::StringData(void) const
{
	return (stringData);
}

const ZafIChar *ZafButton::Text(void)
{
	return (stringData ? stringData->Text() : ZAF_NULLP(ZafIChar));
}

ZafError ZafButton::UpdateBitmap(ZafButton *button, ZafUpdateType type)
{
	ZafError retVal = ZAF_ERROR_INVALID;
	if (type & ZAF_UPDATE_OBJECT)
		retVal = button->OSSetImage();
	if (type & ZAF_UPDATE_DATA)
		retVal = (ZAF_ERROR_NONE);
	return (retVal);
}

ZafError ZafButton::UpdateString(ZafButton *button, ZafUpdateType type)
{
	ZafError retVal = ZAF_ERROR_INVALID;
	if (type & ZAF_UPDATE_OBJECT)
		retVal = button->OSSetText();
	if (type & ZAF_UPDATE_HOT_KEY)
	{
		ZafMessageData *message = DynamicPtrCast(button->StringData(),
			ZafMessageData);
		if (message)
			button->SetHotKey(message->HotKeyChar(), message->HotKeyIndex());
	}
	if (type & ZAF_UPDATE_DATA)
		retVal = (ZAF_ERROR_NONE);
	return (retVal);
}

// ----- Persistent functions -----------------------------------------------
#if defined(USE_ZAF_PERSISTENCE)
ZafButton::ZafButton(const ZafIChar *name, ZafObjectPersistence &persist) :
	ZafWindowObject(name, persist.PushLevel(className, classID, ZAF_PERSIST_DIRECTORY)),
	sendMessageText(ZAF_NULLP(ZafIChar)),
	stringData(ZAF_NULLP(ZafStringData)), bitmapData(ZAF_NULLP(ZafBitmapData)),
	depressed(false)
{
	saveRegion = zafRegion;

	// Check the image information.
	ImageAllocate();

	// Read the data.
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafButton::ReadData(persist);
	persist.PopLevel();
	if (persist.Error() != ZAF_ERROR_NONE)
		SetError(persist.Error());

	// Determine the user function.
	if (SendMessageWhenSelected())
		memberUserFunction = (MemberUserFunction)&ZafButton::SendMessage;
}

ZafElement *ZafButton::Read(const ZafIChar *name, ZafObjectPersistence &persist)
{
	return (new ZafButton(name, persist));
}

void ZafButton::ReadData(ZafObjectPersistence &persist)
{
	// Read the data.
	ZafUInt16 flag1, flag2, flag3;
	ZafIChar imageName[ZAF_MAXNAMELEN], stringName[ZAF_MAXNAMELEN];
	ZafFile *file = persist.CurrentFile();
	*file >> value >> depth >> flag1 >> flag2 >> flag3 >> hotKeyIndex >> stringName >> imageName >> &sendMessageText;
	// flag1
	allowToggling = (flag1 & 0x0001) ? true : false;
	autoRepeatSelection	= (flag1 & 0x0002) ? true : false;
	autoSize = (flag1 & 0x0004) ? true : false;
	selectOnDoubleClick = (flag1 & 0x008) ? true : false;
	selectOnDownClick = (flag1 & 0x0010) ? true : false;
	sendMessageWhenSelected = (flag1 & 0x0020) ? true : false;
	allowDefault = (flag1 & 0x0040) ? true : false;
	buttonType = (ZafButtonType)(((int)flag1 & 0xF000) >> 12);
	if (buttonType == ZAF_FLAT_BUTTON)
		depth = 0;
	// flag2
	hzJustify = (ZafHzJustify)((int)flag2 & 0x000F);
	vtJustify = (ZafVtJustify)(((int)flag2 & 0x00F0) >> 4);
	// flag3
	hotKeyChar = (ZafIChar)flag3;

	// Read the string data.
	if (*stringName)
		SetStringData(new ZafStringData(stringName, persist));

	// Read the bitmap data.
	if (*imageName)
		SetBitmapData(new ZafBitmapData(imageName, persist));
}

void ZafButton::Write(ZafObjectPersistence &persist)
{
	// Write the object.
	ZafRegionStruct tempRegion = zafRegion;
	zafRegion = saveRegion;
	ZafWindowObject::Write(persist.PushLevel(className, classID, ZAF_PERSIST_DIRECTORY));
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafButton::WriteData(persist);
	persist.PopLevel();
	if (persist.Error() != ZAF_ERROR_NONE)
		SetError(persist.Error());
	zafRegion = tempRegion;
}

void ZafButton::WriteData(ZafObjectPersistence &persist)
{
	// Write the general button data.
	ZafUInt16 flag1 = 0, flag2 = 0, flag3;
	// flag1
	flag1 |= (ZafUInt16)(allowToggling  ? 0x0001 : 0);
	flag1 |= (ZafUInt16)(autoRepeatSelection ? 0x0002 : 0);
	flag1 |= (ZafUInt16)(autoSize ? 0x0004 : 0);
	flag1 |= (ZafUInt16)(selectOnDoubleClick ? 0x0008 : 0);
	flag1 |= (ZafUInt16)(selectOnDownClick ? 0x0010 : 0);
	flag1 |= (ZafUInt16)(sendMessageWhenSelected ? 0x0020 : 0);
	flag1 |= (ZafUInt16)(allowDefault  ? 0x0040 : 0);
	flag1 |= (ZafUInt16)((buttonType & 0x000F) << 12);
	// flag2
	flag2 |= (ZafUInt16)(hzJustify & 0x000F);
	flag2 |= (ZafUInt16)((vtJustify & 0x000F) << 4);
	// flag3
	flag3 = (ZafUInt16)hotKeyChar;

	const ZafIChar *stringName = stringData ? stringData->StringID() : ZAF_NULLP(ZafIChar);
	const ZafIChar *imageName = bitmapData ? bitmapData->StringID() : ZAF_NULLP(ZafIChar);
	ZafFile *file = persist.CurrentFile();
	*file << value << depth << flag1 << flag2 << flag3 << hotKeyIndex << stringName << imageName << sendMessageText;

	// Write the string data.
	if (stringData)
		stringData->Write(persist);

	// Write the bitmap data.
	if (bitmapData)
		bitmapData->Write(persist);
}
#endif
