예제 #1
0
파일: eps.cpp 프로젝트: alilloyd/livecode
Exec_stat MCEPS::getprop_legacy(uint4 parid, Properties which, MCExecPoint& ep, Boolean effective)
{
	switch (which)
	{
#ifdef /* MCEPS::getprop */ LEGACY_EXEC
	case P_SIZE:
		ep.setint(size);
		break;
	case P_ANGLE:
		ep.setr8(angle, ep.getnffw(), ep.getnftrailing(), ep.getnfforce());
		break;
	case P_POSTSCRIPT:
		ep.setsvalue(postscript);
		break;
	case P_PROLOG:
		ep.setsvalue(prolog);
		break;
	case P_RETAIN_IMAGE:
		ep.setboolean(getflag(F_RETAIN_IMAGE));
		break;
	case P_RETAIN_POSTSCRIPT:
		ep.setboolean(getflag(F_RETAIN_POSTSCRIPT));
		break;
	case P_SCALE_INDEPENDENTLY:
		ep.setboolean(getflag(F_SCALE_INDEPENDENTLY));
		break;
	case P_BOUNDING_RECT:
		ep.setrectangle(tx, ty, tx + ex, ty + ey);
		break;
	case P_SCALE:
	case P_X_SCALE:
		ep.setr8(xscale, ep.getnffw(), ep.getnftrailing(), ep.getnfforce());
		break;
	case P_Y_SCALE:
		ep.setr8(yscale, ep.getnffw(), ep.getnftrailing(), ep.getnfforce());
		break;
	case P_X_OFFSET:
		ep.setint(tx);
		break;
	case P_Y_OFFSET:
		ep.setint(ty);
		break;
	case P_X_EXTENT:
		ep.setint(ex);
		break;
	case P_Y_EXTENT:
		ep.setint(ey);
		break;
	case P_CURRENT_PAGE:
		ep.setint(MCU_max(curpage, 1));
		break;
	case P_PAGE_COUNT:
		ep.setint(MCU_max(pagecount, 1));
		break;
#endif /* MCEPS::getprop */
	default:
		return MCControl::getprop_legacy(parid, which, ep, effective);
	}
	return ES_NORMAL;
}
예제 #2
0
void MCStack::sethints()
{
	if (!opened || MCnoui || window == DNULL) //not opened or no user interface
		return;
	if (flags & F_RESIZABLE)
	{
		rect.width = MCU_max(minwidth, rect.width);
		rect.width = MCU_min(maxwidth, rect.width);
		rect.width = MCU_min(MCscreen->getwidth(), rect.width);
		rect.height = MCU_max(minheight, rect.height);
		rect.height = MCU_min(maxheight, rect.height);
		rect.height = MCU_min(MCscreen->getheight(), rect.height);
	}
}
예제 #3
0
void MCStack::sethints()
{
	if (!opened || MCnoui || window == DNULL)
		return;
	if (flags & F_RESIZABLE)
	{
		rect.width = MCU_max(minwidth, rect.width);
		rect.width = MCU_min(maxwidth, rect.width);
		rect.height = MCU_max(minheight, rect.height);
		rect.height = MCU_min(maxheight, rect.height);
	}
	MCStack *sptr = MCdefaultstackptr == this ? MCtopstackptr : MCdefaultstackptr;
	if (sptr != NULL && sptr != this && sptr->getw() != DNULL
	        && GetWindowLongA((HWND)window->handle.window, 0) == 0)
		SetWindowLongA((HWND)window->handle.window, 0, (LONG)sptr->getw()->handle.window);
}
예제 #4
0
파일: sysspec.cpp 프로젝트: bduck/livecode
	bool Write(const void *p_buffer, uint32_t p_length, uint32_t& r_written)
	{
		// If we aren't writable then its an error (writable buffers start off with
		// nil buffer pointer, and 0 capacity).
		if (m_buffer != NULL && m_capacity == 0)
			return false;
		
		// If there isn't enough room, extend
		if (m_pointer + p_length > m_capacity)
		{
			uint32_t t_new_capacity;
			t_new_capacity = (m_pointer + p_length + 4096) & ~4095;
			
			void *t_new_buffer;
			t_new_buffer = realloc(m_buffer, t_new_capacity);
			if (t_new_buffer == NULL)
				return false;
			
			m_buffer = static_cast<char *>(t_new_buffer);
			m_capacity = t_new_capacity;
		}
		
		memcpy(m_buffer + m_pointer, p_buffer, p_length);
		m_pointer += p_length;
		m_length = MCU_max(m_pointer, m_length);
		r_written = p_length;
		
		return true;
	}
예제 #5
0
static bool MCParseRGBA(const MCString &p_data, bool p_require_alpha, uint1 &r_red, uint1 &r_green, uint1 &r_blue, uint1 &r_alpha)
{
	bool t_success = true;
	Boolean t_parsed;
	uint2 r, g, b, a;
	const char *t_data = p_data.getstring();
	uint32_t l = p_data.getlength();
	if (t_success)
	{
		r = MCU_max(0, MCU_min(255, MCU_strtol(t_data, l, ',', t_parsed)));
		t_success = t_parsed;
	}
	if (t_success)
	{
		g = MCU_max(0, MCU_min(255, MCU_strtol(t_data, l, ',', t_parsed)));
		t_success = t_parsed;
	}
	if (t_success)
	{
		b = MCU_max(0, MCU_min(255, MCU_strtol(t_data, l, ',', t_parsed)));
		t_success = t_parsed;
	}
	if (t_success)
	{
		a = MCU_max(0, MCU_min(255, MCU_strtol(t_data, l, ',', t_parsed)));
		if (!t_parsed)
		{
			if (p_require_alpha)
				t_success = false;
			else
				a = 255;
		}
	}
	
	if (t_success)
	{
		r_red = r;
		r_green = g;
		r_blue = b;
		r_alpha = a;
	}
	return t_success;
}
예제 #6
0
void RTFListTable::SetStyle(uint32_t p_level, MCTextListStyle p_style)
{
	if (m_list_count == 0)
		return;
	
	p_level = MCU_min(MCU_max(p_level, 1U), 9U);

	if (m_lists[m_list_count - 1] . list_styles[p_level - 1] == kMCTextListStyleNone)
		m_lists[m_list_count - 1] . list_styles[p_level - 1] = p_style;
}
예제 #7
0
static void seekdir_wrapper(DIR *dirp, long loc)
{
	if (dirp -> __dd_fd < 0)
	{
		DIR_wrapper *t_wrapper;
		t_wrapper = (DIR_wrapper *)dirp;
		t_wrapper -> index = MCU_max(MCU_min(loc, (signed)t_wrapper -> entry_count), 0);
		return;
	}
	seekdir_trampoline(dirp, loc);
}
예제 #8
0
bool RTFListTable::Get(int4 p_id, uint32_t p_level, MCTextListStyle& r_style)
{
	p_level = MCU_min(MCU_max(p_level, 1U), 9U);

	for(uint32_t i = 0; i < m_list_count; i++)
		if (m_lists[i] . list_id == p_id)
		{
			r_style = m_lists[i] . list_styles[p_level - 1];
			return true;
		}
	
	return false;
}
예제 #9
0
파일: rtf.cpp 프로젝트: simonasato/livecode
RTFStatus RTFReader::ParseLegacyList(RTFToken p_token, int4 p_value)
{
	RTFStatus t_status;
	t_status = kRTFStatusSuccess;

	RTFToken t_token;
	t_token = p_token & kRTFTokenMask;

	bool t_has_parameter;
	t_has_parameter = (p_token & kRTFTokenHasParameter) != 0;

	switch(t_token)
	{
	case kRTFTokenLegacyListLevel:
		m_list_level = MCU_max(MCU_min(p_value, 9), 1);
		break;
	case kRTFTokenLegacyListBulletLevel:
		m_list_style = kMCTextListStyleDisc;
		m_list_level = 1;
		break;
	case kRTFTokenLegacyListBodyLevel:
		m_list_style = kMCTextListStyleDecimal;
		m_list_level = 1;
		break;
	case kRTFTokenLegacyListDecimalNumbering:
		m_list_style = kMCTextListStyleDecimal;
		break;
	case kRTFTokenLegacyListLowercaseAlphabeticNumbering:
		m_list_style = kMCTextListStyleLowerCaseLetter;
		break;
	case kRTFTokenLegacyListLowercaseRomanNumbering:
		m_list_style = kMCTextListStyleLowerCaseRoman;
		break;
	case kRTFTokenLegacyListUppercaseAlphabeticNumbering:
		m_list_style = kMCTextListStyleUpperCaseLetter;
		break;
	case kRTFTokenLegacyListUppercaseRomanNumbering:
		m_list_style = kMCTextListStyleUpperCaseRoman;
		break;
	case kRTFTokenLegacyListPrefixText:
		m_state . SetDestination(kRTFDestinationLegacyListPrefix);
		break;
	case kRTFTokenLegacyListSuffixText:
		m_state . SetDestination(kRTFDestinationSkip);
		break;
	}

	return t_status;
}
예제 #10
0
static MCStringRef windows_query_locale(uint4 t_index)
{
	// Allocate a buffer for the locale information
	int t_buf_size;
	t_buf_size = GetLocaleInfoW(LOCALE_USER_DEFAULT, t_index, NULL, 0);
	wchar_t* t_buffer = new wchar_t[t_buf_size];
	
	// Get the locale information and create a StringRef from it
	if (GetLocaleInfoW(LOCALE_USER_DEFAULT, t_index, t_buffer, t_buf_size) == 0)
		return MCValueRetain(kMCEmptyString);
	MCStringRef t_string;
	MCStringCreateWithChars(t_buffer, MCU_max(0, t_buf_size - 1), t_string);
	delete[] t_buffer;
	
	return t_string;
}
예제 #11
0
// This method assumes the value is already a string.
bool MCVariableValue::reserve(uint32_t p_required_length, void*& r_buffer, uint32_t& r_length)
{
	if (strnum . buffer . size == 0)
	{
		// If the buffer is 0 size it means we are either empty or we have a constant
		// string assigned.

		// Work out how much space we need.
		uint32_t t_new_size;
		t_new_size = MCU_max(p_required_length, strnum . svalue . length);

		// Attempt to allocate it.
		strnum . buffer . data = (char *)malloc(t_new_size);
		if (strnum . buffer . data == NULL)
			return false;

		// Assign the buffer, and move the svalue over.
		strnum . buffer . size = t_new_size;
		memcpy(strnum . buffer . data, strnum . svalue . string, strnum . svalue . length);
		strnum . svalue . string = strnum . buffer . data;
	}
	else if (p_required_length > strnum . buffer . size)
	{
		// We need more space, so reallocate.
		char *t_new_buffer;
		t_new_buffer = (char *)realloc(strnum . buffer . data, p_required_length);
		if (t_new_buffer == NULL)
			return false;

		// Update the buffer
		strnum . buffer . size = p_required_length;
		
		// And make sure the svalue points to the right place
		strnum . svalue . string = strnum . buffer . data;
	}

	// Return the buffer and existing string length.
	r_buffer = strnum . buffer . data;
	r_length = strnum . svalue . length;

	return true;
}
예제 #12
0
Boolean MCDispatch::openstartup(const char *sname,
                                char **outpath, IO_handle &stream)
{
	if (enginedir == nil)
		return False;

		uint4 l = MCU_max((uint4)strlen(enginedir), (uint4)strlen(startdir)) + strlen(sname) + 11;
		char *fullpath = new char[l];
		sprintf(fullpath, "%s/%s", startdir, sname);
		if ((stream = MCS_open(fullpath, IO_READ_MODE, True, False, 0)) != NULL)
		{
			*outpath = fullpath;
			return True;
		}
		sprintf(fullpath, "%s/%s", enginedir, sname);
		if ((stream = MCS_open(fullpath, IO_READ_MODE, True, False, 0)) != NULL)
		{
			*outpath = fullpath;
			return True;
		}
		delete fullpath;

	return False;
}
예제 #13
0
파일: eps.cpp 프로젝트: alilloyd/livecode
Exec_stat MCEPS::setprop_legacy(uint4 parid, Properties p, MCExecPoint &ep, Boolean effective)
{
	Boolean dirty = True;
	real8 n;
	int2 i;
	int2 i1, i2, i3, i4;
	MCString data = ep.getsvalue();

	switch (p)
	{
#ifdef /* MCEPS::setprop */ LEGACY_EXEC
	case P_TRAVERSAL_ON:
	case P_SHOW_BORDER:
		if (MCControl::setprop(parid, p, ep, effective) != ES_NORMAL)
			return ES_ERROR;
		resetscale();
		break;
	case P_ANGLE:
		if (!MCU_stoi2(data, i))
		{
			MCeerror->add
			(EE_OBJECT_NAN, 0, 0, data);
			return ES_ERROR;
		}
		angle = i;
		break;
	case P_POSTSCRIPT:
		delete postscript;
		postscript = data.clone();
		size = data.getlength() + 1;
		setextents();
		resetscale();
		break;
	case P_PROLOG:
		delete prolog;
		prolog = data.clone();
		break;
	case P_RETAIN_IMAGE:
		if (!MCU_matchflags(data, flags, F_RETAIN_IMAGE, dirty))
		{
			MCeerror->add
			(EE_OBJECT_NAB, 0, 0, data);
			return ES_ERROR;
		}
		dirty = False;
		break;
	case P_RETAIN_POSTSCRIPT:
		if (!MCU_matchflags(data, flags, F_RETAIN_POSTSCRIPT, dirty))
		{
			MCeerror->add
			(EE_OBJECT_NAB, 0, 0, data);
			return ES_ERROR;
		}
		dirty = False;
		break;
	case P_SCALE_INDEPENDENTLY:
		if (!MCU_matchflags(data, flags, F_SCALE_INDEPENDENTLY, dirty))
		{
			MCeerror->add
			(EE_OBJECT_NAB, 0, 0, data);
			return ES_ERROR;
		}
		if (dirty)
			resetscale();
		break;
	case P_BOUNDING_RECT:
		if (!MCU_stoi2x4(data, i1, i2, i3, i4))
		{
			MCeerror->add
			(EE_OBJECT_NAR, 0, 0, data);
			return ES_ERROR;
		}
		if (tx != i1 || ty != i2 || tx + ex != i3 || ty + ey != i4)
		{
			tx = i1;
			ty = i2;
			ex = MCU_max(i3 - i1, 1);
			ey = MCU_max(i4 - i2, 1);
			resetscale();
		}
		else
			dirty = False;
		break;
	case P_SCALE:
		if (!MCU_stor8(data, n))
		{
			MCeerror->add
			(EE_OBJECT_NAN, 0, 0, data);
			return ES_ERROR;
		}
		xscale = yscale = n;
		break;
	case P_X_SCALE:
		if (!MCU_stor8(data, n))
		{
			MCeerror->add
			(EE_OBJECT_NAN, 0, 0, data);
			return ES_ERROR;
		}
		xscale = n;
		ex = (uint2)(rect.width * xf / xscale + 0.5);
		flags |= F_SCALE_INDEPENDENTLY;
		break;
	case P_Y_SCALE:
		if (!MCU_stor8(data, n))
		{
			MCeerror->add
			(EE_OBJECT_NAN, 0, 0, data);
			return ES_ERROR;
		}
		yscale = n;
		ey = (uint2)(rect.height * yf / yscale + 0.5);
		flags |= F_SCALE_INDEPENDENTLY;
		break;
	case P_X_OFFSET:
		if (!MCU_stoi2(data, i))
		{
			MCeerror->add
			(EE_OBJECT_NAN, 0, 0, data);
			return ES_ERROR;
		}
		tx = i;
		break;
	case P_Y_OFFSET:
		if (!MCU_stoi2(data, i))
		{
			MCeerror->add
			(EE_OBJECT_NAN, 0, 0, data);
			return ES_ERROR;
		}
		ty = i;
		break;
	case P_X_EXTENT:
		if (!MCU_stoi2(data, i))
		{
			MCeerror->add
			(EE_OBJECT_NAN, 0, 0, data);
			return ES_ERROR;
		}
		ex = i;
		resetscale();
		break;
	case P_Y_EXTENT:
		if (!MCU_stoi2(data, i))
		{
			MCeerror->add
			(EE_OBJECT_NAN, 0, 0, data);
			return ES_ERROR;
		}
		ey = i;
		resetscale();
		break;
	case P_CURRENT_PAGE:    //set eps current page to display
		if (!MCU_stoi2(data, i))
		{
			MCeerror->add
			(EE_OBJECT_NAN, 0, 0, data);
			return ES_ERROR;
		}
		if ((uint2)i > pagecount)
			curpage = pagecount;
		else
			curpage = i;
		break;
#endif /* MCEPS::setprop */
	default:
		return MCControl::setprop_legacy(parid, p, ep, effective);
	}
	if (dirty && opened)
	{
		// MW-2011-08-18: [[ Layers ]] Invalidate the whole object.
		layer_redrawall();
	}
	return ES_NORMAL;
}
예제 #14
0
Exec_stat MCRepeat::exec(MCExecPoint &ep)
{
	real8 endn = 0.0;
	int4 count = 0;
	MCExecPoint ep2(ep);
	MCScriptPoint *sp = NULL;
	Parse_stat ps;
	const char *sptr;
	uint4 l;
	MCVariableValue *tvar = NULL;
	MCHashentry *hptr = NULL;
	uint4 kindex = 0;
	Boolean donumeric = False;
	Exec_stat stat;
	switch (form)
	{
	case RF_FOR:
		if (loopvar != NULL)
		{
			while ((stat = endcond->eval(ep2)) != ES_NORMAL
			        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
				MCB_error(ep2, getline(), getpos(), EE_REPEAT_BADFORCOND);
			if (stat != ES_NORMAL)
			{
				MCeerror->add(EE_REPEAT_BADFORCOND, line, pos);
				return ES_ERROR;
			}
			if (each == FU_ELEMENT)
			{
				tvar = ep2.getarray();
				if (tvar != NULL && tvar -> is_array())
				{
					l = 1;
					kindex = 0;
					donumeric = tvar -> get_array() -> isnumeric();
					hptr = tvar -> get_array() -> getnextelement(kindex, hptr, donumeric, ep);
					if (hptr == NULL)
					{
						kindex = 0;
						donumeric = False;
						hptr = tvar -> get_array() -> getnextelement(kindex, hptr, donumeric, ep);
					}
				}
				else
					l = 0;
			}
			else if (each == FU_KEY)
			{
				tvar = ep2.getarray();
				if (tvar != NULL && tvar -> is_array())
				{
					l = 1;
					kindex = 0;
					donumeric = False;
					hptr = tvar -> get_array() -> getnextkey(kindex, hptr);
					// [[ Bug 3871 ]] : If hptr is NULL then we are done already (this can happen
					//                  with an empty custom property set).
					if (hptr == NULL)
						l = 0;
				}
				else
					l = 0;
			}
			else
			{
				sptr = ep2.getsvalue().getstring();
				l = ep2.getsvalue().getlength();
				if (each == FU_WORD)
					MCU_skip_spaces(sptr, l);
				else
					if (each == FU_TOKEN)
					{
						sp = new MCScriptPoint(ep2);
						ps = sp->nexttoken();
						if (ps == PS_ERROR || ps == PS_EOF)
							l = 0;
					}
			}
		}
		else
		{
			while (((stat = endcond->eval(ep)) != ES_NORMAL
			        || (stat = ep.ton()) != ES_NORMAL) && (MCtrace || MCnbreakpoints)
			        && !MCtrylock && !MClockerrors)
				MCB_error(ep, getline(), getpos(), EE_REPEAT_BADFORCOND);
			if (stat != ES_NORMAL)
			{
				MCeerror->add
				(EE_REPEAT_BADFORCOND, line, pos);
				return ES_ERROR;
			}
			count = MCU_max(ep.getint4(), 0);
		}
		break;
	case RF_WITH:
		if (step != NULL)
		{
			while (((stat = step->eval(ep)) != ES_NORMAL
			        || (stat = ep.ton()) != ES_NORMAL) && (MCtrace || MCnbreakpoints)
			        && !MCtrylock && !MClockerrors)
				MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWITHSTEP);
			stepval = ep.getnvalue();
			if (stat != ES_NORMAL || stepval == 0.0)
			{
				MCeerror->add
				(EE_REPEAT_BADWITHSTEP, line, pos);
				return ES_ERROR;
			}
		}
		while (((stat = startcond->eval(ep)) != ES_NORMAL
		        || (stat = ep.ton()) != ES_NORMAL) && (MCtrace || MCnbreakpoints)
		        && !MCtrylock && !MClockerrors)
			MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWITHSTART);
		if (stat != ES_NORMAL)
		{
			MCeerror->add
			(EE_REPEAT_BADWITHSTART, line, pos);
			return ES_ERROR;
		}
		ep.setnvalue(ep.getnvalue() - stepval);
		while ((stat = loopvar->set
		               (ep)) != ES_NORMAL
		        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
			MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWITHVAR);
		if (stat != ES_NORMAL)
		{
			MCeerror->add
			(EE_REPEAT_BADWITHVAR, line, pos);
			return ES_ERROR;
		}
		while (((stat = endcond->eval(ep)) != ES_NORMAL
		        || (stat = ep.ton()) != ES_NORMAL)
		        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
			MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWITHEND);
		if (stat != ES_NORMAL)
		{
			MCeerror->add
			(EE_REPEAT_BADWITHEND, line, pos);
			return ES_ERROR;
		}
		endn = ep.getnvalue();
		break;
	default:
		break;
	}

	MCString s;
	Boolean done = False;
	bool t_first;
	t_first = false;
	while (True)
	{
		switch (form)
		{
		case RF_FOREVER:
			break;
		case RF_FOR:
			if (loopvar != NULL)
			{
				if (l == 0)
				{
					done = True;
					// OK-2007-12-05 : Bug 5605. If there has been at least one iteration, set the loop variable to 
					// whatever the value was in the last iteration. 
					if (!t_first)
					{
						// MW-2011-02-08: [[ Bug ]] Make sure we don't use 's' if the repeat type is 'key' or
						//   'element'.
						if (each != FU_ELEMENT && each != FU_KEY)
						{
							ep.setsvalue(s);
							loopvar->set(ep);
						}
					}
				}
				else
				{
					const char *startptr; // = sptr;
					switch (each)
					{
					case FU_KEY:
						// MW-2010-12-15: [[ Bug 9218 ]] Make a copy of the key so that it can't be mutated
						//   accidentally.
						ep . setstaticcstring(hptr -> string);
						loopvar -> set(ep);
						hptr = tvar -> get_array() -> getnextkey(kindex, hptr);
						if (hptr == NULL)
							l = 0;
						break;
					case FU_ELEMENT:
						hptr -> value . fetch(ep);
						loopvar -> set(ep);
						hptr = tvar -> get_array() -> getnextelement(kindex, hptr, donumeric, ep);
						if (hptr == NULL)
							l = 0;
						break;
					case FU_LINE:
						startptr = sptr;
						if (!MCU_strchr(sptr, l, ep.getlinedel()))
						{
							sptr += l;
							l = 0;
						}
						s.set(startptr, sptr - startptr);
						MCU_skip_char(sptr, l);
						break;
					case FU_ITEM:
						startptr = sptr;
						if (!MCU_strchr(sptr, l, ep.getitemdel()))
						{
							sptr += l;
							l = 0;
						}
						s.set(startptr, sptr - startptr);
						MCU_skip_char(sptr, l);
						break;
					case FU_WORD:
						startptr = sptr;
						if (*sptr == '\"')
						{
							MCU_skip_char(sptr, l);
							while (l && *sptr != '\"' && *sptr != '\n')
								MCU_skip_char(sptr, l);
							MCU_skip_char(sptr, l);
						}
						else
							while (l && !isspace((uint1)*sptr))
								MCU_skip_char(sptr, l);
						s.set(startptr, sptr - startptr);
						MCU_skip_spaces(sptr, l);
						break;
					case FU_TOKEN:
						s = sp->gettoken();
						ps = sp->nexttoken();
						if (ps == PS_ERROR || ps == PS_EOF)
							l = 0;
						break;
					case FU_CHARACTER:
					default:
						startptr = sptr;
						s.set(startptr, 1);
						MCU_skip_char(sptr, l);
					}
					// MW-2010-12-15: [[ Bug 9218 ]] Added KEY to the type of repeat that already
					//   copies the value.
					if (each != FU_ELEMENT && each != FU_KEY)
					{
						if (MCtrace)
						{
							ep.setsvalue(s);
							loopvar->set(ep);
						}
						else
							loopvar->sets(s);
					}
				}
			}
			else
				done = count-- == 0;
			break;
		case RF_UNTIL:
			while ((stat = endcond->eval(ep)) != ES_NORMAL
			        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
				MCB_error(ep, getline(), getpos(), EE_REPEAT_BADUNTILCOND);
			if (stat != ES_NORMAL)
			{
				MCeerror->add
				(EE_REPEAT_BADUNTILCOND, line, pos);
				return ES_ERROR;
			}
			done = ep.getsvalue() == MCtruemcstring;
			break;
		case RF_WHILE:
			while ((stat = endcond->eval(ep)) != ES_NORMAL
			        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
				MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWHILECOND);
			if (stat != ES_NORMAL)
			{
				MCeerror->add
				(EE_REPEAT_BADWHILECOND, line, pos);
				return ES_ERROR;
			}
			done = ep.getsvalue() != MCtruemcstring;
			break;
		case RF_WITH:
			while (((stat = loopvar->eval(ep)) != ES_NORMAL
			        || (stat = ep.ton()) != ES_NORMAL)
			        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
				MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWITHVAR);
			if (stat != ES_NORMAL)
			{
				MCeerror->add
				(EE_REPEAT_BADWITHVAR, line, pos);
				return ES_ERROR;
			}
			if (stepval < 0)
			{
				if (ep.getnvalue() <= endn)
					done = True;
			}
			else
				if (ep.getnvalue() >= endn)
					done = True;
			if (!done)
			{
				ep.setnvalue(ep.getnvalue() + stepval);
				while ((stat = loopvar->set
				               (ep)) != ES_NORMAL
				        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
					MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWITHVAR);
				if (stat != ES_NORMAL)
				{
					MCeerror->add
					(EE_REPEAT_BADWITHVAR, line, pos);
					return ES_ERROR;
				}
			}
			break;
		default:
			break;
		}
		if (done)
			break;

		Exec_stat stat;
		MCStatement *tspr = statements;
		while (tspr != NULL)
		{
			if (MCtrace || MCnbreakpoints)
			{
				MCB_trace(ep, tspr->getline(), tspr->getpos());
				if (MCexitall)
					break;
			}
			ep.setline(tspr->getline());

			stat = tspr->exec(ep);

			// MW-2011-08-17: [[ Redraw ]] Flush any screen updates.
			MCRedrawUpdateScreen();
			
			switch(stat)
			{
			case ES_NORMAL:
				if (MCexitall)
				{
					// OK-2007-12-05 : Bug 5605 : If exiting loop, set the loop variable to the value it had
					//   in the last iteration.
					// MW-2011-02-08: [[ Bug ]] Make sure we don't use 's' if the repeat type is 'key' or
					//   'element'.
					if (form == RF_FOR && loopvar != NULL && each != FU_ELEMENT && each != FU_KEY)
					{
						ep.setsvalue(s);
						loopvar->set(ep);
					}
					delete sp;
					return ES_NORMAL;
				}
				tspr = tspr->getnext();
				break;
			case ES_NEXT_REPEAT:
				tspr = NULL;
				break;
			case ES_EXIT_REPEAT:
				// OK-2007-12-05 : Bug 5605 : If exiting loop, set the loop variable to the value it had
				//   in the last iteration.
				// MW-2011-02-08: [[ Bug ]] Make sure we don't use 's' if the repeat type is 'key' or
				//   'element'.
				if (form == RF_FOR && loopvar != NULL && each != FU_ELEMENT && each != FU_KEY)
				{
					ep.setsvalue(s);
					loopvar->set(ep);
				}
				delete sp;
				return ES_NORMAL;
			case ES_ERROR:
				if ((MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
					do
					{
						MCB_error(ep, tspr->getline(), tspr->getpos(),
						          EE_REPEAT_BADSTATEMENT);
					}
					while (MCtrace && (stat = tspr->exec(ep)) != ES_NORMAL);
				if (stat == ES_ERROR)
				{
					// OK-2007-12-05 : Bug 5605 : If exiting loop, set the loop variable to the value it had
					//   in the last iteration.
					// MW-2011-02-08: [[ Bug ]] Make sure we don't use 's' if the repeat type is 'key' or
					//   'element'.
					if (form == RF_FOR && loopvar != NULL && each != FU_ELEMENT && each != FU_KEY)
					{
						ep.setsvalue(s);
						loopvar->set(ep);
					}
					delete sp;
					if (MCexitall)
						return ES_NORMAL;
					else
					{
						MCeerror->add(EE_REPEAT_BADSTATEMENT, line, pos);
						return ES_ERROR;
					}
				}
				else
					tspr = tspr->getnext();
				break;
			default:
				// OK-2007-12-05 : Bug 5605 : If exiting loop, set the loop variable to the value it had
				//   in the last iteration.
				// MW-2011-02-08: [[ Bug ]] Make sure we don't use 's' if the repeat type is 'key' or
				//   'element'.
				if (form == RF_FOR && loopvar != NULL && each != FU_ELEMENT && each != FU_KEY)
				{
					ep.setsvalue(s);
					loopvar->set(ep);
				}
				delete sp;
				return stat;
			}
		}
		if (MCscreen->abortkey())
		{
			// OK-2007-12-05 : Bug 5605 : If exiting loop, set the loop variable to the value it had
			//   in the last iteration.
			// MW-2011-02-08: [[ Bug ]] Make sure we don't use 's' if the repeat type is 'key' or
			//   'element'.
			if (form == RF_FOR && loopvar != NULL && each != FU_ELEMENT && each != FU_KEY)
			{
				ep.setsvalue(s);
				loopvar->set(ep);
			}
			delete sp;
			MCeerror->add(EE_REPEAT_ABORT, line, pos);
			return ES_ERROR;
		}
		if (MCtrace || MCnbreakpoints)
		{
			MCB_trace(ep, getline(), getpos());
			if (MCexitall)
				break;
		}

		t_first = false;
	}
	delete sp;
	return ES_NORMAL;
}
예제 #15
0
/// This is a helper function for the layout methods, and does not check any printing status.
/// Thus, it is assumed that this is done at a higher level.
/// The function returns true if a page break is required.
bool MCPrinter::CalculateLayout(const MCRectangle& p_src_rect, MCRectangle& r_dst_rect)
{
    int32_t t_dst_width;
    t_dst_width = (int32_t)ceil(m_layout_scale * p_src_rect . width);

    int32_t t_dst_height;
    t_dst_height = (int32_t)ceil(m_layout_scale * p_src_rect . height);

    int32_t t_maximum_x;
    t_maximum_x = m_page_width - m_page_right_margin;

    int32_t t_maximum_y;
    t_maximum_y = m_page_height - m_page_bottom_margin;

    bool t_require_break;
    t_require_break = false;

    if (m_loop_layout_x != m_page_left_margin || m_loop_layout_y != m_page_top_margin)
    {
        if (m_layout_rows_first)
        {
            if (m_loop_layout_x + t_dst_width > t_maximum_x)
            {
                m_loop_layout_x = m_page_left_margin;
                m_loop_layout_y += m_layout_row_spacing + m_loop_layout_delta;
                m_loop_layout_delta = t_dst_height;
                if (m_loop_layout_y + t_dst_height > t_maximum_y)
                    t_require_break = true;
            }
        }
        else
        {
            if (m_loop_layout_y + t_dst_height > t_maximum_y)
            {
                m_loop_layout_y = m_page_top_margin;
                m_loop_layout_x += m_layout_column_spacing + m_loop_layout_delta;
                m_loop_layout_delta = t_dst_width;
                if (m_loop_layout_x + t_dst_width > t_maximum_x)
                    t_require_break = true;
            }
        }
    }

    if (t_require_break)
    {
        m_loop_layout_x = m_page_left_margin;
        m_loop_layout_y = m_page_top_margin;
    }

    r_dst_rect . x = m_loop_layout_x;
    r_dst_rect . y = m_loop_layout_y;
    r_dst_rect . width = t_dst_width;
    r_dst_rect . height = t_dst_height;

    if (m_layout_rows_first)
    {
        m_loop_layout_delta = MCU_max(m_loop_layout_delta, t_dst_height);
        m_loop_layout_x += m_layout_column_spacing + t_dst_width;
    }
    else
    {
        m_loop_layout_delta = MCU_max(m_loop_layout_delta, t_dst_width);
        m_loop_layout_y += m_layout_row_spacing + t_dst_height;
    }

    return t_require_break;
}
예제 #16
0
Exec_stat MCAudioClip::setprop(uint4 parid, Properties p, MCExecPoint &ep, Boolean effective)
{
	int2 i1;
	MCString data = ep.getsvalue();

	switch (p)
	{
#ifdef /* MCAudioClip::setprop */ LEGACY_EXEC
	case P_PLAY_DESTINATION:
	case P_PLAY_LOUDNESS:
		if (p == P_PLAY_DESTINATION)
		{
			if (data == "external")
				flags |= F_EXTERNAL;
			else
				flags &= ~F_EXTERNAL;
		}
		else
		{
			if (!MCU_stoi2(data, i1))
			{
				MCeerror->add
				(EE_ACLIP_LOUDNESSNAN, 0, 0, data);
				return ES_ERROR;
			}
			loudness = MCU_max(MCU_min(i1, 100), 0);
			if (loudness == 100)
				flags &= ~F_LOUDNESS;
			else
				flags |= F_LOUDNESS;
		}
		if (this == MCtemplateaudio)
		{
			extern bool MCSystemSetPlayLoudness(uint2 loudness);
#ifdef _MOBILE
			if (MCSystemSetPlayLoudness(loudness))
				return ES_NORMAL;
#endif
			if (MCplayers != NULL)
			{
				MCPlayer *tptr = MCplayers;
				while (tptr != NULL)
				{
					tptr->setvolume(loudness);
					tptr = tptr->getnextplayer();
				}
			}
#if defined _WINDOWS
			WORD v = loudness * MAXUINT2 / 100;
			if (hwaveout != NULL)
				waveOutSetVolume(hwaveout, v | (v << 16));
			else
			{
				WAVEFORMATEX pwfx;
				pwfx.wFormatTag = WAVE_FORMAT_PCM;
				pwfx.nChannels = 1;
				pwfx.nSamplesPerSec = 22050;
				pwfx.nAvgBytesPerSec = 22050;
				pwfx.nBlockAlign = 1;
				pwfx.wBitsPerSample = 8;
				pwfx.cbSize = 0;
				if (waveOutOpen(&hwaveout, WAVE_MAPPER, &pwfx, 0, 0,
								CALLBACK_NULL | WAVE_ALLOWSYNC) == MMSYSERR_NOERROR)
				{
					waveOutSetVolume(hwaveout, v | (v << 16));
					waveOutClose(hwaveout);
					hwaveout = NULL;
				}
			}

#elif defined _MACOSX
			long volume = loudness * 255 / 100;
			SetDefaultOutputVolume(volume | volume << 16);
#elif defined TARGET_PLATFORM_LINUX
			if ( x11audio != NULL)
				x11audio -> setloudness ( loudness ) ;
#endif

		}
		return ES_NORMAL;
#endif /* MCAudioClip::setprop */
	default:
		break;
	}
	return MCObject::setprop(parid, p, ep, effective);
}
예제 #17
0
void MCStack::effectrect(const MCRectangle& p_area, Boolean& r_abort)
{
	// Get the list of effects.
	MCEffectList *t_effects = MCcur_effects;
	MCcur_effects = NULL;

	// If the window isn't opened or hasn't been attached (plugin) or if we have no
	// snapshot to use, this is a no-op.
	if (!opened || !haswindow() || m_snapshot == nil)
	{
		while(t_effects != NULL)
		{
			MCEffectList *t_effect;
			t_effect = t_effects;
			t_effects = t_effects -> next;
			delete t_effect;
		}
		return;
	}

	// Mark the stack as being in an effect.
	state |= CS_EFFECT;

	// Lock messages while the effect is happening.
	Boolean t_old_lockmessages;
	t_old_lockmessages = MClockmessages;
	MClockmessages = True;

	// Calculate the area of interest.
	MCRectangle t_effect_area;
	t_effect_area = curcard -> getrect();
	t_effect_area . y = getscroll();
	t_effect_area . height -= t_effect_area . y;
	t_effect_area = MCU_intersect_rect(t_effect_area, p_area);
	
	// IM-2013-08-21: [[ ResIndependence ]] Scale effect area to device coords
	// Align snapshot rect to device pixels
	// IM-2013-09-30: [[ FullscreenMode ]] Use stack transform to get device coords
	MCGAffineTransform t_transform;
	t_transform = getdevicetransform();
	
    // MW-2013-10-29: [[ Bug 11330 ]] Make sure the effect area is cropped to the visible
    //   area.
    t_effect_area = MCRectangleGetTransformedBounds(t_effect_area, getviewtransform());
    t_effect_area = MCU_intersect_rect(t_effect_area, MCU_make_rect(0, 0, view_getrect() . width, view_getrect() . height));
	
	// IM-2014-01-24: [[ HiDPI ]] scale effect region to backing surface coords
	MCGFloat t_scale;
	t_scale = view_getbackingscale();
	
    MCRectangle t_device_rect, t_user_rect;
	t_device_rect = MCRectangleGetScaledBounds(t_effect_area, t_scale);
	t_user_rect = MCRectangleGetTransformedBounds(t_device_rect, MCGAffineTransformInvert(t_transform));
	
	// IM-2013-08-29: [[ RefactorGraphics ]] get device height for CoreImage effects
	// IM-2013-09-30: [[ FullscreenMode ]] Use view rect to get device height
	uint32_t t_device_height;
	t_device_height = floor(view_getrect().height * t_scale);
	
	// Make a region of the effect area
	// IM-2013-08-29: [[ ResIndependence ]] scale effect region to device coords
	MCRegionRef t_effect_region;
	t_effect_region = nil;
	/* UNCHECKED */ MCRegionCreate(t_effect_region);
	/* UNCHECKED */ MCRegionSetRect(t_effect_region, t_effect_area);
	
#ifndef FEATURE_PLATFORM_PLAYER
#if defined(FEATURE_QUICKTIME)
	// MW-2010-07-07: Make sure QT is only loaded if we actually are doing an effect
	if (t_effects != nil)
		if (!MCdontuseQTeffects)
			if (!MCtemplateplayer -> isQTinitted())
				MCtemplateplayer -> initqt();
#endif	
#endif

	// Lock the screen to prevent any updates occuring until we want them.
	MCRedrawLockScreen();

	// By default, we have not aborted.
	r_abort = False;
	
	MCGImageRef t_initial_image;
	t_initial_image = MCGImageRetain(m_snapshot);
	
	while(t_effects != nil)
	{
		uint32_t t_duration;
		t_duration = MCU_max(1, MCeffectrate / (t_effects -> speed - VE_VERY));
		if (t_effects -> type == VE_DISSOLVE)
			t_duration *= 2;
		
		uint32_t t_delta;
		t_delta = 0;
		
		// Create surface at effect_area size.
		// Render into surface based on t_effects -> image
		MCGImageRef t_final_image = nil;
		
		// If this isn't a plain effect, then we must fetch first and last images.
		if (t_effects -> type != VE_PLAIN)
		{
			// Render the final image.
			MCGContextRef t_context = nil;
			
			// IM-2014-05-20: [[ GraphicsPerformance ]] Create opaque context for snapshot
			/* UNCHECKED */ MCGContextCreate(t_device_rect.width, t_device_rect.height, false, t_context);
			
			MCGContextTranslateCTM(t_context, -t_device_rect.x, -t_device_rect.y);
			
			// IM-2013-10-03: [[ FullscreenMode ]] Apply device transform to context
			MCGContextConcatCTM(t_context, t_transform);
			
			// Configure the context.
			MCGContextClipToRect(t_context, MCRectangleToMCGRectangle(t_user_rect));
			
			// Render an appropriate image
			switch(t_effects -> image)
			{
				case VE_INVERSE:
					{
						MCContext *t_old_context = nil;
						/* UNCHECKED */ t_old_context = new MCGraphicsContext(t_context);
						curcard->draw(t_old_context, t_user_rect, false);
						delete t_old_context;
						
						MCGContextSetFillRGBAColor(t_context, 1.0, 1.0, 1.0, 1.0);
						MCGContextSetBlendMode(t_context, kMCGBlendModeDifference);
						MCGContextAddRectangle(t_context, MCRectangleToMCGRectangle(t_user_rect));
						MCGContextFill(t_context);
					}
					break;
					
				case VE_BLACK:
					MCGContextSetFillRGBAColor(t_context, 0.0, 0.0, 0.0, 1.0);
					MCGContextAddRectangle(t_context, MCRectangleToMCGRectangle(t_user_rect));
					MCGContextFill(t_context);
					break;
					
				case VE_WHITE:
					MCGContextSetFillRGBAColor(t_context, 1.0, 1.0, 1.0, 1.0);
					MCGContextAddRectangle(t_context, MCRectangleToMCGRectangle(t_user_rect));
					MCGContextFill(t_context);
					break;
					
				case VE_GRAY:
					MCGContextSetFillRGBAColor(t_context, 0.5, 0.5, 0.5, 1.0);
					MCGContextAddRectangle(t_context, MCRectangleToMCGRectangle(t_user_rect));
					MCGContextFill(t_context);
					break;
					
				default:
				{
					MCContext *t_old_context = nil;
					/* UNCHECKED */ t_old_context = new MCGraphicsContext(t_context);
					curcard->draw(t_old_context, t_user_rect, false);
					delete t_old_context;
				}
			}
			
			/* UNCHECKED */ MCGContextCopyImage(t_context, t_final_image);
			MCGContextRelease(t_context);
		}
		
		MCStackEffectContext t_context;
		t_context.delta = t_delta;
		t_context.duration = t_duration;
		t_context.effect = t_effects;
		t_context.effect_area = t_device_rect;
		t_context.initial_image = t_initial_image;
		t_context.final_image = t_final_image;
		
		// MW-2011-10-20: [[ Bug 9824 ]] Make sure dst point is correct.
		// Initialize the destination with the start image.
		view_platform_updatewindowwithcallback(t_effect_region, MCStackRenderInitial, &t_context);
		
		// If there is a sound, then start playing it.
		if (t_effects -> sound != NULL)
		{
			MCAudioClip *acptr;
            MCNewAutoNameRef t_sound;
            /* UNCHECKED */ MCNameCreate(t_effects->sound, &t_sound);
			if ((acptr = (MCAudioClip *)getobjname(CT_AUDIO_CLIP, *t_sound)) == NULL)
			{
				IO_handle stream;
				if ((stream = MCS_open(t_effects->sound, kMCOpenFileModeRead, True, False, 0)) != NULL)
				{
					acptr = new MCAudioClip;
					acptr->setdisposable();
					if (!acptr->import(t_effects->sound, stream))
					{
						delete acptr;
						acptr = NULL;
					}
					MCS_close(stream);
				}
			}
			
			if (acptr != NULL)
			{
				MCU_play_stop();
				MCacptr = acptr;
				MCU_play();
#ifndef FEATURE_PLATFORM_AUDIO
				if (MCacptr != NULL)
					MCscreen->addtimer(MCacptr, MCM_internal, PLAY_RATE);
#endif
			}
			
			if (MCscreen->wait((real8)MCsyncrate / 1000.0, False, True))
			{
				r_abort = True;
				break;
			}
		}
		
		// Initialize CoreImage of QTEffects if needed.
		if (t_effects -> type != VE_PLAIN)
		{
            MCAutoPointer<char> t_name;
            /* UNCHECKED */ MCStringConvertToCString(t_effects -> name, &t_name);
#ifdef _MAC_DESKTOP
			// IM-2013-08-29: [[ ResIndependence ]] use scaled effect rect for CI effects
			if (t_effects -> type == VE_UNDEFINED && MCCoreImageEffectBegin(*t_name, t_initial_image, t_final_image, t_device_rect, t_device_height, t_effects -> arguments))
				t_effects -> type = VE_CIEFFECT;
			else
#endif
#ifdef FEATURE_QUICKTIME_EFFECTS
				// IM-2013-08-29: [[ ResIndependence ]] use scaled effect rect for QT effects
				if (t_effects -> type == VE_UNDEFINED && MCQTEffectBegin(t_effects -> type, *t_name, t_effects -> direction, t_initial_image, t_final_image, t_device_rect))
					t_effects -> type = VE_QTEFFECT;
#else
				;
#endif
		}
		
		// Run effect
		// Now perform the effect loop, but only if there is something to do.
		if (t_effects -> type != VE_PLAIN || old_blendlevel != blendlevel)
		{
			// Calculate timing parameters.
			double t_start_time;
			t_start_time = 0.0;
			
			for(;;)
			{
				t_context.delta = t_delta;
				
				Boolean t_drawn = False;
				view_platform_updatewindowwithcallback(t_effect_region, MCStackRenderEffect, &t_context);
				
				// Now redraw the window with the new image.
//				if (t_drawn)
				{
					MCscreen -> sync(getw());
				}
				
				// Update the window's blendlevel (if needed)
				if (old_blendlevel != blendlevel)
				{
					float t_fraction = float(t_delta) / t_duration;
					setopacity(uint1((old_blendlevel * 255 + (float(blendlevel) - old_blendlevel) * 255 * t_fraction) / 100));
				}
				
				// If the start time is zero, then start counting from here.
				if (t_start_time == 0.0)
					t_start_time = MCS_time();
				
				// If we've reached the end of the transition, we are done.
				if (t_delta == t_duration)
				{
#ifdef _ANDROID_MOBILE
					// MW-2011-12-12: [[ Bug 9907 ]] Make sure we let the screen sync at this point
					MCscreen -> wait(0.01, False, False);
#endif
					break;
				}
				
				// Get the time now.
				double t_now;
				t_now = MCS_time();
				
				// Compute the new delta value.
				uint32_t t_new_delta;
				t_new_delta = (uint32_t)ceil((t_now - t_start_time) * 1000.0);
				
				// If the new value is same as the old, then advance one step.
				if (t_new_delta == t_delta)
					t_delta = t_new_delta + 1;
				else
					t_delta = t_new_delta;
				
				// If the new delta is beyond the end point, set it to the end.
				if (t_delta > t_duration)
					t_delta = t_duration;
				
				// Wait until the next boundary, making sure we break for no reason
				// other than abort.
				if (MCscreen -> wait((t_start_time + (t_delta / 1000.0)) - t_now, False, False))
					r_abort = True;
				
				// If we aborted, we render the final step and are thus done.
				if (r_abort)
					t_delta = t_duration;
			}
		}		
#ifdef _MAC_DESKTOP
		if (t_effects -> type == VE_CIEFFECT)
			MCCoreImageEffectEnd();
		else
#endif
#ifdef FEATURE_QUICKTIME_EFFECTS
			if (t_effects -> type == VE_QTEFFECT)
				MCQTEffectEnd();
#endif
		
		// Free initial surface.
		MCGImageRelease(t_initial_image);
		
		// initial surface becomes final surface.
		t_initial_image = t_final_image;
		t_final_image = nil;
		
		// Move to the next effect.
		MCEffectList *t_current_effect;
		t_current_effect = t_effects;
		t_effects = t_effects -> next;
		delete t_current_effect;
	}

	// Make sure the pixmaps are freed and any dangling effects
	// are cleaned up.
	if (t_effects != NULL)
	{
		/* OVERHAUL - REVISIT: error cleanup needs revised */
		MCGImageRelease(t_initial_image);
//		MCGSurfaceRelease(t_final_image);

		while(t_effects != NULL)
		{
			MCEffectList *t_current_effect;
			t_current_effect = t_effects;
			t_effects = t_effects -> next;
			delete t_current_effect;
		}
	}

	MCRegionDestroy(t_effect_region);
	
	MCGImageRelease(m_snapshot);
	m_snapshot = nil;
	
	m_snapshot = t_initial_image;
	
	// Unlock the screen.
	MCRedrawUnlockScreen();
	
	// Unlock messages.
	MClockmessages = t_old_lockmessages;

	// Turn off effect mode.
	state &= ~CS_EFFECT;
	
	// The stack's blendlevel is now the new one.
	old_blendlevel = blendlevel;
	
	// Finally, mark the affected area of the stack for a redraw.
	dirtyrect(p_area);
}
예제 #18
0
Boolean MCScrollbar::mfocus(int2 x, int2 y)
{
	// MW-2007-09-18: [[ Bug 1650 ]] Disabled state linked to thumb size
	if (!(flags & F_VISIBLE || MCshowinvisibles)
	        || issbdisabled() && getstack()->gettool(this) == T_BROWSE)
		return False;
	if (state & CS_SCROLL)
	{
		// I.M. [[bz 9559]] disable scrolling where start value & end value are the same
		if (startvalue == endvalue)
			return True;

		real8 newpos;

		double t_thumbsize = thumbsize;
		if (t_thumbsize > fabs(endvalue - startvalue))
			t_thumbsize = fabs(endvalue - startvalue);
		if (flags & F_SCALE)
			t_thumbsize = 0;

		bool t_forward;
		t_forward = (endvalue > startvalue);
		MCRectangle t_bar_rect, t_thumb_rect, t_thumb_start_rect, t_thumb_end_rect;
		t_bar_rect = compute_bar();
		t_thumb_rect = compute_thumb(markpos);
		t_thumb_start_rect = compute_thumb(startvalue);
		if (t_forward)
			t_thumb_end_rect = compute_thumb(endvalue - t_thumbsize);
		else
			t_thumb_end_rect = compute_thumb(endvalue + t_thumbsize);

		int32_t t_bar_start, t_bar_length, t_thumb_start, t_thumb_length;
		int32_t t_movement;
		if (getstyleint(flags) == F_VERTICAL)
		{
			t_bar_start = t_thumb_start_rect.y;
			t_bar_length = t_thumb_end_rect.y + t_thumb_end_rect.height - t_bar_start;
			t_thumb_start = t_thumb_rect.y;
			t_thumb_length = t_thumb_rect.height;
			t_movement = y - my;
		}
		else
		{
			t_bar_start = t_thumb_start_rect.x;
			t_bar_length = t_thumb_end_rect.x + t_thumb_end_rect.width - t_bar_start;
			t_thumb_start = t_thumb_rect.x;
			t_thumb_length = t_thumb_rect.width;
			t_movement = x - mx;
		}

		t_bar_start += t_thumb_length / 2;
		t_bar_length -= t_thumb_length;

        // AL-2013-07-26: [[ Bug 11044 ]] Prevent divide by zero when computing scrollbar thumbposition
        if (t_bar_length == 0)
            t_bar_length = 1;
        
		int32_t t_new_position;
		t_new_position = t_thumb_start + t_thumb_length / 2 + t_movement;
		t_new_position = MCU_min(t_bar_start + t_bar_length, MCU_max(t_bar_start, t_new_position));
		
		if (t_forward)
			newpos = startvalue + ((t_new_position - t_bar_start) / (double)t_bar_length) * (fabs(endvalue - startvalue) - t_thumbsize);
		else
			newpos = startvalue - ((t_new_position - t_bar_start) / (double)t_bar_length) * (fabs(endvalue - startvalue) - t_thumbsize);

		update(newpos, MCM_scrollbar_drag);
		return True;
	}
	else if (!MCdispatcher -> isdragtarget() && MCcurtheme && MCcurtheme->getthemepropbool(WTHEME_PROP_SUPPORTHOVERING)
	         && MCU_point_in_rect(rect, x, y) )
	{
		if (!(state & CS_MFOCUSED) && !getstate(CS_SELECTED))
		{
			MCWidgetInfo winfo;
			winfo.type = (Widget_Type)getwidgetthemetype();
			if (MCcurtheme->iswidgetsupported(winfo.type))
			{
				getwidgetthemeinfo(winfo);
				Widget_Part wpart = MCcurtheme->hittest(winfo,mx,my,rect);
				if (wpart != hover_part)
				{
					hover_part = wpart;
					// MW-2011-08-18: [[ Layers ]] Invalidate the whole object.
					redrawall();
				}
			}
		}
	}
	return MCControl::mfocus(x, y);
}