示例#1
0
MCFontnode::MCFontnode(MCNameRef fname, uint2 &size, uint2 style)
{
	reqname = fname;
	reqsize = size;
	reqstyle = style;
    
#if defined(TARGET_SUBPLATFORM_IPHONE)
	font = new MCFontStruct;
	font -> size = size;
	
	uindex_t t_comma;
	MCAutoStringRef reqname_str;
	reqname_str = MCNameGetString(*reqname);
	Boolean t_success;
	t_success = MCStringFirstIndexOfChar(*reqname_str, ',', 0, kMCCompareExact, t_comma);

    MCAutoStringRef t_before_comma;
    /* UNCHECKED */ MCStringCopySubstring(*reqname_str, MCRangeMake(0, t_comma - 1), &t_before_comma);

    font -> fid = (MCSysFontHandle)iphone_font_create(*t_before_comma, reqsize, (reqstyle & FA_WEIGHT) > 0x05, (reqstyle & FA_ITALIC) != 0);

	font -> ascent = size - 1;
	font -> descent = size * 2 / 14 + 1;
	
	float ascent, descent;
	iphone_font_get_metrics(font -> fid,  ascent, descent);
	if (ceilf(ascent) + ceilf(descent) > size)
		font -> ascent++;
    
#elif defined(TARGET_SUBPLATFORM_ANDROID)
	font = new MCFontStruct;
	font -> size = size;
	
	uindex_t t_comma;
	MCAutoStringRef reqname_str;
	reqname_str = MCNameGetString(*reqname);
	Boolean t_success;
	t_success = MCStringFirstIndexOfChar(*reqname_str, ',', 0, kMCCompareExact, t_comma);

    MCAutoStringRef t_before_comma;
    /* UNCHECKED */ MCStringCopySubstring(*reqname_str, MCRangeMake(0, t_comma - 1), &t_before_comma);
    font -> fid = (MCSysFontHandle)android_font_create(*t_before_comma, reqsize, (reqstyle & FA_WEIGHT) > 0x05, (reqstyle & FA_ITALIC) != 0);
	
	font -> ascent = size - 1;
	font -> descent = size * 2 / 14 + 1;
	
	float ascent, descent;
	android_font_get_metrics(font -> fid,  ascent, descent);
	if (ceilf(ascent) + ceilf(descent) > size)
		font -> ascent++;
	
#endif
}
示例#2
0
文件: eps.cpp 项目: alilloyd/livecode
Boolean MCEPS::import(MCStringRef fname, IO_handle stream)
{
	size = (uint4)MCS_fsize(stream);
	delete postscript;
	postscript = new char[size + 1];
	if (IO_read(postscript, size, stream) != IO_NORMAL)
		return False;
	postscript[size] = '\0';
	uindex_t t_sep;
    MCStringRef t_fname;
    if (MCStringLastIndexOfChar(fname, PATH_SEPARATOR, UINDEX_MAX, kMCCompareExact, t_sep))
        /* UNCHECKED */ MCStringCopySubstring(fname, MCRangeMake(t_sep + 1, MCStringGetLength(fname) - (t_sep + 1)), t_fname);
    else
        t_fname = MCValueRetain(fname);
    
    MCNewAutoNameRef t_name;
    if (!MCNameCreateAndRelease(t_fname, &t_name))
        return False;
    setname(*t_name);
	setextents();
	rect.width = (uint2)(ex * xscale / xf);
	rect.height = (uint2)(ey * yscale / yf);
	if (flags & F_SHOW_BORDER)
	{
		rect.width += borderwidth << 1;
		rect.height += borderwidth << 1;
	}
	return True;
}
示例#3
0
void MCPlatformHandleTextInputQueryTextRect(MCPlatformWindowRef p_window, MCRange p_range, MCRectangle& r_first_line_rect, MCRange& r_actual_range)
{
	if (!MCactivefield)
	{
		r_first_line_rect = MCRectangleMake(0, 0, 0, 0);
		r_actual_range = MCRangeMake(UINDEX_MAX, 0);
		return;
	}
	
	int32_t t_si, t_ei;
	t_si = 0;
	t_ei = INT32_MAX;
	MCactivefield -> resolvechars(0, t_si, t_ei, p_range . offset, p_range . length);
	
	MCRectangle t_rect;
	t_rect = MCactivefield -> firstRectForCharacterRange(t_si, t_ei);
	
	MCactivefield -> unresolvechars(0, t_si, t_ei);
	
	MCPoint t_top_left, t_bottom_right;
	t_top_left = MCactivefield -> getstack() -> stacktowindowloc(MCPointMake(t_rect . x, t_rect . y));
	t_bottom_right = MCactivefield -> getstack() -> stacktowindowloc(MCPointMake(t_rect . x + t_rect . width, t_rect . y + t_rect . height));
	
	r_first_line_rect = MCRectangleMake(t_top_left . x, t_top_left . y, t_bottom_right . x - t_top_left . x, t_bottom_right . y - t_top_left . y);
	r_actual_range = MCRangeMakeMinMax(t_si, t_ei);
}
示例#4
0
void MCPlatformHandleTextInputQueryTextRanges(MCPlatformWindowRef p_window, MCRange& r_marked_range, MCRange& r_selected_range)
{
	if (!MCactivefield)
	{
		r_marked_range = MCRangeMake(UINDEX_MAX, 0);
		r_selected_range = MCRangeMake(UINDEX_MAX, 0);
		return;
	}
	
	int4 si, ei;
	MCactivefield -> selectedmark(False, si, ei, False);
	MCactivefield -> unresolvechars(0, si, ei);
	r_selected_range = MCRangeMakeMinMax(si, ei);
	if (MCactivefield -> getcompositionrange(si, ei))
	{
		MCactivefield -> unresolvechars(0, si, ei);
		r_marked_range = MCRangeMakeMinMax(si, ei);
	}
	else
		r_marked_range = MCRangeMake(UINDEX_MAX, 0);
}
示例#5
0
bool MCArraysSplitIndexes(MCNameRef p_key, integer_t*& r_indexes, uindex_t& r_count, bool& r_all_integers)
{
	r_indexes = nil;
	r_count = 0;

	MCStringRef t_string = MCNameGetString(p_key);
	uindex_t t_string_len = MCStringGetLength(t_string);
	if (t_string_len == 0)
		return true;

	r_all_integers = true;
    
    uindex_t t_start, t_finish;    
    t_start = 0;
    t_finish = 0;
    
	for(;;)
	{
        if (!MCStringFirstIndexOfChar(t_string, ',', t_start, kMCCompareExact, t_finish))
            t_finish = t_string_len;
        		
		if (!MCMemoryResizeArray(r_count + 1, r_indexes, r_count))
			return false;
        
        MCAutoStringRef t_substring;
        MCAutoNumberRef t_number;
        MCStringCopySubstring(t_string, MCRangeMake(t_start, t_finish - t_start), &t_substring);
        
        if (!MCNumberParse(*t_substring, &t_number))
        {
            r_indexes[r_count - 1] = 0;
            r_all_integers = false;
            break;
        }
        else
            r_indexes[r_count - 1] = MCNumberFetchAsInteger(*t_number);

		if (t_finish >= t_string_len)
			break;

		t_start = t_finish + 1;
	}

	return true;
}
示例#6
0
void MCPlatformHandleTextInputQueryText(MCPlatformWindowRef p_window, MCRange p_range, unichar_t*& r_chars, uindex_t& r_char_count, MCRange& r_actual_range)
{
    if (!MCactivefield)
    {
        r_chars = nil;
        r_char_count = 0;
        r_actual_range = MCRangeMake(p_range . offset, 0);
        return;
    }
    
	int32_t t_si, t_ei;
    MCAutoStringRef t_text;
	t_si = 0;
	t_ei = INT32_MAX;
	MCactivefield -> resolvechars(0, t_si, t_ei, p_range . offset, p_range . length);
    
    MCactivefield -> exportastext(0, t_si, t_ei, &t_text);
    
	MCactivefield -> unresolvechars(0, t_si, t_ei);
    
    /* UNCHECKED */ MCStringConvertToUnicode(*t_text, r_chars, r_char_count);
    r_actual_range = MCRangeMakeMinMax(t_si, t_ei);
}
示例#7
0
void MCArraysExecSplitByColumn(MCExecContext& ctxt, MCStringRef p_string, MCArrayRef& r_array)
{
    MCStringRef t_row_delim, t_column_delim;
    t_row_delim = ctxt . GetRowDelimiter();
    t_column_delim = ctxt . GetColumnDelimiter();
    
    // Output array
    MCAutoArrayRef t_array;
    if (!MCArrayCreateMutable(&t_array))
    {
        ctxt . Throw();
        return;
    }
    
    // Temporary array for storing columns
    MCAutoArray<MCStringRef> t_temp_array;
    
    // Iterate over the rows of the input string
    uindex_t t_offset, t_length;
    t_offset = 0;
    t_length = MCStringGetLength(p_string);
    
    bool t_success;
    t_success = true;
    
    uindex_t t_row_index;
    t_row_index = 0;
    
    while (t_success && t_offset < t_length)
    {
        // Find the end of this row
        MCRange t_row_found;
        if (!MCStringFind(p_string, MCRangeMake(t_offset, UINDEX_MAX), t_row_delim, ctxt . GetStringComparisonType(), &t_row_found))
        {
            t_row_found . offset = t_length;
            t_row_found . length = 0;
        }
        
        // Iterate over the cells of this row
        uindex_t t_cell_offset, t_column_index;
        t_cell_offset = t_offset;
        t_column_index = 0;
        while (t_success && t_cell_offset <= t_row_found . offset)
        {
            // Find the end of this cell
            MCRange t_cell_found;
            if (!MCStringFind(p_string, MCRangeMake(t_cell_offset, UINDEX_MAX), t_column_delim, ctxt . GetStringComparisonType(), &t_cell_found) || t_cell_found . offset > t_row_found . offset)
            {
                t_cell_found . offset = t_row_found . offset;
                // AL-2014-08-04: [[ Bug 13090 ]] Make sure cell offset is incremented eventually when the delimiter is not found
                t_cell_found . length = 1;
            }
            
            // Check that the output array has a slot for this column
            if (t_temp_array.Size() <= t_column_index)
                t_temp_array.Extend(t_column_index + 1);
            
            // Check that a string has been created to store this column
            MCRange t_range;
            t_range = MCRangeMake(t_cell_offset, t_cell_found . offset - t_cell_offset);
            if (t_temp_array[t_column_index] == nil)
            {
                t_success = MCStringCreateMutable(0, t_temp_array[t_column_index]);
                
                // AL-2014-08-04: [[ Bug 13090 ]] If we are creating a new column, make sure we pad with empty cells 'above' this one
                uindex_t t_rows = t_row_index;
                while (t_success && t_rows--)
                    t_success = MCStringAppend(t_temp_array[t_column_index], t_row_delim);
                
                if (t_success)
                    t_success = MCStringAppendFormat(t_temp_array[t_column_index], "%*@", &t_range, p_string);
            }
            else
            {
                // AL-2014-06-12: [[ Bug 12610 ]] Range parameter to MCStringFormat must be a pointer to an MCRange
                t_success = MCStringAppendFormat(t_temp_array[t_column_index], "%@%*@", t_row_delim, &t_range, p_string);
            }
            
            // Next cell
            t_column_index++;
            t_cell_offset = t_cell_found . offset + t_cell_found . length;
        }
        
        // AL-2014-08-04: [[ Bug 13090 ]] Pad the rest of this row with empty cells
        index_t t_pad_number;
        t_pad_number = t_temp_array . Size() - t_column_index;
        if (t_success && t_pad_number > 0)
        {
            while (t_success && t_pad_number--)
                t_success = MCStringAppend(t_temp_array[t_column_index++], t_row_delim);
        }
        
        // Next row
        t_row_index++;
        t_offset = t_row_found . offset + t_row_found . length;
    }
    
    // Convert the temporary array into a "proper" array
    for (uindex_t i = 0; i < t_temp_array.Size() && t_success; i++)
    {
        t_success = MCArrayStoreValueAtIndex(*t_array, i + 1, t_temp_array[i]);
        MCValueRelease(t_temp_array[i]);
    }

    if (t_success)
        t_success = MCArrayCopy(*t_array, r_array);
    
    if (!t_success)
        ctxt . Throw();
}
示例#8
0
// SN-2014-09-01: [[ Bug 13297 ]] Combining by column deserves its own function as it is too
// different from combining by row
void MCArraysExecCombineByColumn(MCExecContext& ctxt, MCArrayRef p_array, MCStringRef &r_string)
{    
    MCStringRef t_row_delimiter, t_col_delimiter;
    t_row_delimiter = ctxt . GetRowDelimiter();
    t_col_delimiter = ctxt . GetColumnDelimiter();
    
    MCAutoListRef t_list;
    MCListCreateMutable(t_row_delimiter, &t_list);
    
    uindex_t t_count = MCArrayGetCount(p_array);
    combine_int_indexed_array_t t_lisctxt;
    bool t_success;
    
    t_lisctxt . elements = nil;
    t_lisctxt . index = 0;
    t_lisctxt . converter = &ctxt;
    t_success = MCMemoryNewArray(t_count, t_lisctxt . elements);
    
    if (t_success)
    {
        if (MCArrayApply(p_array, list_int_indexed_array_elements, &t_lisctxt))
        {
            bool t_valid_keys;
            
            qsort(t_lisctxt . elements, t_count, sizeof(array_element_t), compare_int_indexed_elements);
            
            // Combine by row/column is only valid if all the indices are consecutive numbers
            // Otherwise, an empty string is returned - no error
            index_t t_last_index;
            t_valid_keys = true;
            t_last_index = 0;
            for (int i = 0; i < t_count && t_valid_keys; ++i)
            {
                if (!t_last_index)
                    t_last_index = t_lisctxt . elements[i] . key;
                else
                    t_valid_keys = ++t_last_index == t_lisctxt . elements[i] . key;
            }
            
            if (t_valid_keys)
            {
                // SN-2014-09-01: [[ Bug 13297 ]]
                // We need to store the converted strings in a array, to be able to iterate through the elements by one row-delimitated
                //  at a time
                MCStringRef* t_strings;
                uindex_t *t_next_row_indices;
                
                t_strings = NULL;
                t_next_row_indices = NULL;
                
                /* UNCHECKED */ MCMemoryNewArray(t_count, t_strings);
                // MCMemoryNewArray initialises all t_next_row_indices elements to 0.
                /* UNCHECKED */ MCMemoryNewArray(t_count, t_next_row_indices);
                
                for (int i = 0; i < t_count && t_success; ++i)
                {
                    if (t_lisctxt . elements[i] . key == 0) // The index 0 is ignored
                        continue;
                    
                    t_success = ctxt . ConvertToString(t_lisctxt . elements[i] . value, t_strings[i]);
                }
                
                // SN-2014-09-01: [[ Bug 13297 ]] Added a missed part in column-combining:
                // only combining row-by-row the array elements.
                if (t_success)
                {
                    uindex_t t_elements_over;
                    t_elements_over = 0;
                    
                    // We iterate as long as one element still has uncombined rows
                    while (t_success && t_elements_over != t_count)
                    {
                        MCAutoListRef t_row;
                        
                        t_success = MCListCreateMutable(t_col_delimiter, &t_row);
                        t_elements_over = 0;
                        
                        // Iterate through all the elements of the array
                        for (int i = 0; i < t_count && t_success; ++i)
                        {
                            // Only consider this element if it has any uncombined rows remaining
                            if (t_next_row_indices[i] < MCStringGetLength(t_strings[i]))
                            {
                                MCRange t_cell_range;
                                if (MCStringFind(t_strings[i], MCRangeMake(t_next_row_indices[i], UINDEX_MAX), t_row_delimiter, ctxt.GetStringComparisonType(), &t_cell_range))
                                {
                                    // We found a row delimiter, so we stop the copy range before it and update the next index from which to look
                                    t_success = MCListAppendSubstring(*t_row, t_strings[i], MCRangeMake(t_next_row_indices[i], t_cell_range . offset - t_next_row_indices[i]));
                                    t_next_row_indices[i] = t_cell_range . offset + t_cell_range . length;
                                }
                                else
                                {
                                    // No row delimiter: we copy the remaining part of the string and mark the element
                                    // as wholly combined by setting the next index to the length of the element
                                    t_success = MCListAppendSubstring(*t_row, t_strings[i], MCRangeMake(t_next_row_indices[i], UINDEX_MAX));
                                    t_next_row_indices[i] = MCStringGetLength(t_strings[i]);
                                }
                            }
                            else
                            {
                                // Everything has been combined in this element
                                t_elements_over++;
                                MCListAppend(*t_row, kMCEmptyString);
                            }
                        }
                        
                        // One more row has been combined - doing it anyway mimics the previous behaviour of having an empty row
                        // added in the end when combining by columns
                        if (t_elements_over != t_count)
                            MCListAppend(*t_list, *t_row);
                    }
                }
                
                MCMemoryDeleteArray(t_next_row_indices);
                MCMemoryDeleteArray(t_strings);
            }
        }
        MCMemoryDeleteArray(t_lisctxt . elements);
    }
    
    if (t_success && MCListCopyAsString(*t_list, r_string))
        return;
    
    ctxt . Throw();
}
示例#9
0
Exec_stat MCF_parsetextatts(Properties which, MCStringRef data,
                            uint4 &flags, MCStringRef &fname, uint2 &height,
                            uint2 &size, uint2 &style)
{
	int2 i1;
	switch (which)
	{
	case P_TEXT_ALIGN:
		flags &= ~F_ALIGNMENT;
		if (MCStringIsEqualToCString(data, MCleftstring, kMCCompareCaseless) || MCStringIsEmpty(data))
			flags |= F_ALIGN_LEFT;
		else
			if (MCStringIsEqualToCString(data, MCcenterstring, kMCCompareCaseless))
				flags |= F_ALIGN_CENTER;
			else
				if (MCStringIsEqualToCString(data, MCrightstring, kMCCompareCaseless))
					flags |= F_ALIGN_RIGHT;
				else
					if (MCStringIsEqualToCString(data, MCjustifystring, kMCCompareCaseless))
						flags |= F_ALIGN_JUSTIFY;
					else
					{
						MCeerror->add(EE_OBJECT_BADALIGN, 0, 0, data);
						return ES_ERROR;
					}
		break;
	case P_TEXT_FONT:
		{// MW-2012-02-17: [[ IntrinsicUnicode ]] Strip any lang tag from the
			//   fontname.
			uindex_t t_offset;
			if (MCStringFirstIndexOfChar(data, ',', 0, kMCCompareExact, t_offset))
				/* UNCHECKED */ MCStringCopySubstring(data, MCRangeMake(t_offset + 1, MCStringGetLength(data) - (t_offset + 1)), fname);
			else
				fname = MCValueRetain(data);
		}
		break;
	case P_TEXT_HEIGHT:
		if (!MCU_stoi2(data, i1))
		{
			MCeerror->add
			(EE_OBJECT_TEXTHEIGHTNAN, 0, 0, data);
			return ES_ERROR;
		}
		height = i1;
		break;
	case P_TEXT_SIZE:
		if (MCStringIsEmpty(data))
			i1 = 0;
		else
			if (!MCU_stoi2(data, i1))
			{
				MCeerror->add
				(EE_OBJECT_TEXTSIZENAN, 0, 0, data);
				return ES_ERROR;
			}
		size = i1;
		break;
	case P_TEXT_STYLE:
		{
			// MW-2012-02-17: [[ SplitTextAttrs ]] If the string is empty, then
			//   return 0 for the style - indicating to unset the property.
            if (MCStringIsEmpty(data))
				style = 0;
			else
            {
                style = FA_DEFAULT_STYLE;
                uindex_t t_start_pos, t_end_pos;
                t_end_pos = 0;
                
                while (t_end_pos < MCStringGetLength(data))
                {
                    t_start_pos = t_end_pos;
                    // skip spaces at the beginning or after a comma (if any)
                    MCU_skip_spaces(data, t_start_pos);
                    
                    uindex_t t_comma;
                    if (!MCStringFirstIndexOfChar(data, ',', t_start_pos, kMCCompareExact, t_comma))
                        t_end_pos = MCStringGetLength(data);
                    else
                        t_end_pos = t_comma;
                    
                    MCAutoStringRef tdata;
                    /* UNCHECKED */ MCStringCopySubstring(data, MCRangeMake(t_start_pos, t_end_pos - t_start_pos), &tdata);
                    t_end_pos++;
                    if (MCF_setweightstring(style, *tdata))
						continue;
					if (MCF_setexpandstring(style, *tdata))
						continue;
					if (MCF_setslantlongstring(style, *tdata))
						continue;
					if (MCStringIsEqualToCString(*tdata, MCplainstring, kMCCompareCaseless))
					{
						style = FA_DEFAULT_STYLE;
						continue;
					}
					if (MCStringIsEqualToCString(*tdata, MCmixedstring, kMCCompareCaseless))
					{
						style = FA_DEFAULT_STYLE;
						continue;
					}
					if (MCStringIsEqualToCString(*tdata, MCboxstring, kMCCompareCaseless))
					{
						style &= ~FA_3D_BOX;
						style |= FA_BOX;
						continue;
                    }
                
					if (MCStringIsEqualToCString(*tdata, MCthreedboxstring, kMCCompareCaseless))
					{
						style &= ~FA_BOX;
						style |= FA_3D_BOX;
						continue;
					}
					if (MCStringIsEqualToCString(*tdata, MCunderlinestring, kMCCompareCaseless))
					{
						style |= FA_UNDERLINE;
						continue;
					}
					if (MCStringIsEqualToCString(*tdata, MCstrikeoutstring, kMCCompareCaseless))
					{
						style |= FA_STRIKEOUT;
						continue;
					}
					if (MCStringIsEqualToCString(*tdata, MCgroupstring, kMCCompareCaseless) || MCStringIsEqualToCString(*tdata, MClinkstring, kMCCompareCaseless))
					{
						style |= FA_LINK;
						continue;
					}
					MCeerror->add(EE_OBJECT_BADSTYLE, 0, 0, data);
					return ES_ERROR;
				}
			}
		}
		break;
	default:
		break;
	}
	return ES_NORMAL;
}
示例#10
0
void MCFontDrawText(MCGContextRef p_gcontext, int32_t x, int32_t y, MCStringRef p_text, MCFontRef font, bool p_rtl, bool p_can_break)
{
	MCRange t_range = MCRangeMake(0, MCStringGetLength(p_text));
	return MCFontDrawTextSubstring(p_gcontext, x, y, p_text, t_range, font, p_rtl, p_can_break);
}
示例#11
0
int32_t MCFontMeasureText(MCFontRef p_font, MCStringRef p_text, const MCGAffineTransform &p_transform)
{
	MCRange t_range = MCRangeMake(0, MCStringGetLength(p_text));
    return MCFontMeasureTextSubstring(p_font, p_text, t_range, p_transform);
}
示例#12
0
void MCFontBreakText(MCFontRef p_font, MCStringRef p_text, MCRange p_range, MCFontBreakTextCallback p_callback, void *p_callback_data, bool p_rtl)
{
	// MW-2013-12-19: [[ Bug 11559 ]] If the font has a nil font, do nothing.
	if (p_font -> fontstruct == nil)
		return;

    // If the text is small enough, don't bother trying to break it
    /*if (p_length <= (kMCFontBreakTextCharLimit * (p_is_unicode ? 2 : 1)))
    {
        p_callback(p_font, p_text, p_length, p_is_unicode, p_callback_data);
        return;
    }*/
    
    //p_callback(p_font, p_text, p_length, p_is_unicode, p_callback_data);
    //return;
    
    // Scan forward in the string for possible break locations. Breaks are
    // assigned a quality value as some locations are better for breaking than
    // others. The qualities are:
    //
    //  0.  no break found
    //  1.  grapheme break found
    //  2.  URL break found ('/' char)
    //  3.  word break found
    //
    // This isn't a particularly good algorithm but should suffice until full
    // Unicode support is added and a proper breaking algorithm implemented.
    uint32_t t_stride;
    t_stride = kMCFontBreakTextCharLimit;
    
    uindex_t t_end = p_range.offset + p_range.length;
    
    uindex_t t_length = p_range.length;
    uindex_t t_offset = (p_rtl) ? 0 : p_range.offset;
    
    while (t_length > 0)
    {
        int t_break_quality;
        uindex_t t_break_point, t_index;

        t_break_quality = 0;
        t_break_point = 0;
        t_index = 0;

        // Find the best break within the next stride characters. If there are
        // no breaking points, extend beyond the stride until one is found.
        while ((t_index < t_stride || t_break_quality == 0) && t_index < t_length)
        {
            codepoint_t t_char;
            uindex_t t_advance;
            
            if (p_rtl)
                t_char = MCStringGetCharAtIndex(p_text, t_end - t_index - t_offset);
            else
                t_char = MCStringGetCharAtIndex(p_text, t_offset + t_index);
            
            if (MCUnicodeCodepointIsHighSurrogate(t_char))
            {
                // Surrogate pair
                if (p_rtl)
                    t_char = MCUnicodeSurrogatesToCodepoint(t_char, MCStringGetCharAtIndex(p_text, t_end - t_index - t_offset - 1));
                else
                    t_char = MCUnicodeSurrogatesToCodepoint(t_char, MCStringGetCharAtIndex(p_text, t_offset + t_index + 1));
                
                t_advance = 2;
            }
            else
            {
                t_advance = 1;
            }
            
            // Prohibit breaks at the beginning of the string
            if (t_index == 0)
            {
                t_index += t_advance;
                continue;
            }
            
            if (t_char == ' ')
            {
                t_break_point = t_index;
                t_break_quality = 3;
            }
            else if (t_break_quality < 3 && t_char == '/')
            {
                t_break_point = t_index;
                t_break_quality = 2;
            }
            else if (t_break_quality < 2 && MCUnicodeCodepointIsBase(t_char))
            {
                t_break_point = t_index;
                t_break_quality = 1;
            }
            else if (t_break_quality < 2 && t_char > 0xFFFF)
            {
                // Character outside BMP, assume can break here
                t_break_point = t_index;
                t_break_quality = 1;
            }
            
            // If the break point is a word boundary, don't look for a later
            // breaking point. Words are cached as-is where possible.
            if (t_break_quality == 3)
                break;
            
            // Advance to the next character
            t_index += t_advance;
        }
        
        // If no word break was found and the whole of the remaining text was
        // searched and the remaining text is smaller than the break size then
        // don't attempt a break just for the sake of it.
        if (t_break_quality < 3 && t_length < kMCFontBreakTextCharLimit)
            t_break_point = t_length;
        
        // If no break point was found, just process the whole line
        if (t_break_quality == 0)
            t_break_point = t_length;
        
        // Process this chunk of text
        MCRange t_range;
        if (p_rtl)
            t_range = MCRangeMake(t_end - t_offset - t_break_point, t_break_point);
        else
            t_range = MCRangeMake(t_offset, t_break_point);

#if !defined(_WIN32) && !defined(_ANDROID_MOBILE)
        // This is a really ugly hack to get LTR/RTL overrides working correctly -
        // ATSUI and Pango think they know better than us and won't let us suppress
        // the BiDi algorithm they uses for text layout. So instead, we need to add
        // an LRO or RLO character in front of every single bit of text :-(
        MCAutoStringRef t_temp;
        unichar_t t_override;
        if (p_rtl)
            t_override = 0x202E;
        else
            t_override = 0x202D;
        /* UNCHECKED */ MCStringCreateMutable(0, &t_temp);
        /* UNCHECKED */ MCStringAppendChar(*t_temp, t_override);
        /* UNCHECKED */ MCStringAppendSubstring(*t_temp, p_text, t_range);
        /* UNCHECKED */ MCStringAppendChar(*t_temp, 0x202C);
        
        p_callback(p_font, *t_temp, MCRangeMake(0, MCStringGetLength(*t_temp)), p_callback_data);
#else
        // Another ugly hack - this time, to avoid incoming strings being coerced
        // into Unicode strings needlessly (because the drawing code uses unichars).
        // Do a mutable copy (to ensure an actual copy) before drawing.
        MCAutoStringRef t_temp;
        /* UNCHECKED */ MCStringMutableCopySubstring(p_text, t_range, &t_temp);
        p_callback(p_font, *t_temp, MCRangeMake(0, t_range.length), p_callback_data);
#endif
        
        // Explicitly show breaking points
        //p_callback(p_font, MCSTR("|"), MCRangeMake(0, 1), p_callback_data);
        
        // Move on to the next chunk
        t_offset += t_break_point;
        // SN-2014-07-23: [[ Bug 12910 ]] Script editor crashes
        //  Make sure we get 0 as a minimum, not a negative value since t_length is a uindex_t.
        if (t_length < t_break_point)
            t_length = 0;
        else
            t_length -= t_break_point;
    }
}
示例#13
0
void MCKeywordsExecRepeatFor(MCExecContext& ctxt, MCStatement *statements, MCExpression *endcond, MCVarref *loopvar, File_unit each, uint2 line, uint2 pos)
{
    MCAutoArrayRef t_array;
    MCAutoStringRef t_string;
    MCAutoDataRef t_data;
    MCRange t_chunk_range;
    t_chunk_range = MCRangeMake(0,0);
    uindex_t t_length = 0;
    MCAutoValueRef t_condition;
	MCNameRef t_key;
	MCValueRef t_value;
	uintptr_t t_iterator;
    // SN2015-06-15: [[ Bug 15457 ]] The index can be a negative index.
    index_t t_sequenced_iterator;
    const byte_t *t_data_ptr;
    
    MCAutoPointer<MCTextChunkIterator> tci;
    
    if (!ctxt . TryToEvaluateExpression(endcond, line, pos, EE_REPEAT_BADFORCOND, &t_condition))
        return;
    
    bool t_sequence_array;
    t_sequence_array = false;

    if (each == FU_ELEMENT || each == FU_KEY)
    {
        if (!ctxt . ConvertToArray(*t_condition, &t_array))
            return;
        
        // SN-2015-06-15: [[ Bug 15457 ]] If this is a numerical array, do
        //  it in order - even if it does not start at 1
        if (each == FU_ELEMENT && MCArrayIsNumericSequence(*t_array, t_sequenced_iterator))
        {
            t_sequence_array = true;
            if (!MCArrayFetchValueAtIndex(*t_array, t_sequenced_iterator, t_value))
                return;
        }
        else
        {
            t_iterator = 0;
            if (!MCArrayIterate(*t_array, t_iterator, t_key, t_value))
                return;
        }
    }
    else if (each == FU_BYTE)
    {
        if (!ctxt . ConvertToData(*t_condition, &t_data))
            return;
        
        t_length = MCDataGetLength(*t_data);
        t_data_ptr = MCDataGetBytePtr(*t_data);
    }
    else
    {
        if (!ctxt . ConvertToString(*t_condition, &t_string))
            return;
        
        switch (each)
        {
            case FU_LINE:
                tci = MCStringsTextChunkIteratorCreate(ctxt, *t_string, CT_LINE);
                break;
            case FU_PARAGRAPH:
                tci = MCStringsTextChunkIteratorCreate(ctxt, *t_string, CT_PARAGRAPH);
                break;
            case FU_SENTENCE:
                tci = MCStringsTextChunkIteratorCreate(ctxt, *t_string, CT_SENTENCE);
                break;
            case FU_ITEM:
                tci = MCStringsTextChunkIteratorCreate(ctxt, *t_string, CT_ITEM);
                break;
            case FU_WORD:
                tci = MCStringsTextChunkIteratorCreate(ctxt, *t_string, CT_WORD);
                break;
            case FU_TRUEWORD:
                tci = MCStringsTextChunkIteratorCreate(ctxt, *t_string, CT_TRUEWORD);
                break;
            case FU_TOKEN:
                tci = MCStringsTextChunkIteratorCreate(ctxt, *t_string, CT_TOKEN);
                break;
            case FU_CODEPOINT:
                tci = MCStringsTextChunkIteratorCreate(ctxt, *t_string, CT_CODEPOINT);
                break;
            case FU_CODEUNIT:
                tci = MCStringsTextChunkIteratorCreate(ctxt, *t_string, CT_CODEUNIT);
                break;
            case FU_CHARACTER:
            default:
                tci = MCStringsTextChunkIteratorCreate(ctxt, *t_string, CT_CHARACTER);
                break;
        } 
    }
    
    bool done;
    done = false;
    
    bool endnext;
    endnext = false;
    
    bool t_found;
    t_found = false;
    
    while (!done)
    {
        MCAutoStringRef t_unit;
        MCAutoDataRef t_byte;
        switch (each)
        {
            case FU_KEY:
            {
                loopvar -> set(ctxt, t_key);
                if (!MCArrayIterate(*t_array, t_iterator, t_key, t_value))
                    endnext = true;
            }
            break;
                
            case FU_ELEMENT:
            {
                loopvar -> set(ctxt, t_value);
                // SN-2015-06-15: [[ Bug 15457 ]] Sequenced, numeric arrays
                //  have their own iterator
                if (t_sequence_array)
                {
                    if (!MCArrayFetchValueAtIndex(*t_array, ++t_sequenced_iterator, t_value))
                        endnext = true;
                }
                else
                {
                    if (!MCArrayIterate(*t_array, t_iterator, t_key, t_value))
                        endnext = true;
                }
            }
            break;
            
            case FU_BYTE:
            {
                // SN-2014-04-14 [[ Bug 12184 ]] If we have no data at all, we don't want to start the loop
                if (t_length)
                {
                    MCDataCreateWithBytes(t_data_ptr++, 1, &t_byte);
                    
                    endnext = (--t_length) == 0;
                }
                else
                    done = true;
            }
            break;
                
            default:
            {
                t_found = MCStringsTextChunkIteratorNext(ctxt, *tci);
                endnext = tci -> IsExhausted();
                
                if (!t_found)
                {
                    t_unit = kMCEmptyString;
                    done = true;
                }
                else
                    tci -> CopyString(&t_unit);
            }
            break;
        }
        // MW-2010-12-15: [[ Bug 9218 ]] Added KEY to the type of repeat that already
        //   copies the value.
        // MW-2011-02-08: [[ Bug ]] Make sure we don't use 't_unit' if the repeat type is 'key' or
        //   'element'.
        // Set the loop variable to whatever the value was in the last iteration.
        if (each == FU_BYTE)
        {
            // SN-2014-04-14 [[ Bug 12184 ]] We don't need to set anything since we are not going in the loop
            if (!done)
                loopvar -> set(ctxt, *t_byte);
        }
        else if (each != FU_ELEMENT && each != FU_KEY)
            loopvar -> set(ctxt, *t_unit);
        
        if (!done)
            MCKeywordsExecuteRepeatStatements(ctxt, statements, line, pos, done);
        
        if (endnext)
        {
            // Reset the loop variable to whatever the value was in the last iteration.
            if (loopvar != nil)
            {
                if (each == FU_BYTE)
                    loopvar -> set(ctxt, *t_byte);
                else if (each != FU_ELEMENT && each != FU_KEY)
                    loopvar -> set(ctxt, *t_unit);
            }
        }
        
        done = done || endnext;
    }
}
示例#14
0
static int MCA_do_file_dialog(MCStringRef p_title, MCStringRef p_prompt, MCStringRef p_filter, MCStringRef p_initial, unsigned int p_options, MCStringRef &r_value, MCStringRef &r_result)
{
	int t_result = 0;

	MCAutoStringRef t_initial_file;
	MCAutoStringRef t_initial_folder;
    MCAutoStringRef t_initial_native_folder;

	if (p_initial != nil && !MCStringIsEmpty(p_initial))
	{
		MCAutoStringRef t_fixed_path;
		/* UNCHECKED */ MCU_fix_path(p_initial, &t_fixed_path);

		if (MCS_exists(*t_fixed_path, False))
			t_initial_folder = *t_fixed_path;
		else if ((p_options & MCA_OPTION_SAVE_DIALOG) != 0)
		{
			uindex_t t_last_slash;
			if (!MCStringLastIndexOfChar(*t_fixed_path, '/', UINDEX_MAX, kMCStringOptionCompareExact, t_last_slash))
			{
				if (MCStringGetLength(*t_fixed_path) != 0)
					t_initial_file = *t_fixed_path;
			}
			else
			{
				if (t_last_slash < MCStringGetLength(*t_fixed_path) - 1)
					/* UNCHECKED */ MCStringCopySubstring(*t_fixed_path, MCRangeMake(t_last_slash + 1, MCStringGetLength(*t_fixed_path) - (t_last_slash + 1)), &t_initial_file);

				MCAutoStringRef t_folder_split;
				/* UNCHECKED */ MCStringCopySubstring(*t_fixed_path, MCRangeMake(0, t_last_slash - 1), &t_folder_split);
				if (MCS_exists(*t_folder_split, False))
					t_initial_folder = *t_folder_split;
			}
		}
		else
		{
			uindex_t t_last_slash;

			if (MCStringLastIndexOfChar(*t_fixed_path, '/', UINDEX_MAX, kMCStringOptionCompareExact, t_last_slash))
			{
				MCAutoStringRef t_folder_split;
				/* UNCHECKED */ MCStringCopySubstring(*t_fixed_path, MCRangeMake(0, t_last_slash - 1), &t_folder_split);
				
				if (MCS_exists(*t_folder_split, False))
					t_initial_folder = *t_folder_split;
			}
		}
        
        MCAutoStringRef t_resolved_folder;
        /* UNCHECKED */ MCS_resolvepath(*t_initial_folder != nil ? *t_initial_folder : kMCEmptyString, &t_resolved_folder);
        /* UNCHECKED */ MCS_pathtonative(*t_resolved_folder, &t_initial_native_folder);
	}
    
	if (!MCModeMakeLocalWindows())
	{
		MCAutoStringRefArray t_filters;

		if (p_filter != NULL)
		{
			/* UNCHECKED */ MCStringsSplit(p_filter, '\0', t_filters.PtrRef(), t_filters.CountRef());
		}

		MCRemoteFileDialog(p_title, p_prompt, *t_filters, t_filters.Count(), *t_initial_native_folder, *t_initial_file, (p_options & MCA_OPTION_SAVE_DIALOG) != 0, (p_options & MCA_OPTION_PLURAL) != 0, r_value);

		return 0;
	}

	Window t_window;
	t_window = MCModeGetParentWindow();

	MCAutoStringRef t_value;
	bool t_succeeded;
	int t_filter_index;

	if (MCmajorosversion >= 0x0600)
	{
		static SHCreateItemFromParsingNamePtr  s_shcreateitemfromparsingname = NULL;
		if (s_shcreateitemfromparsingname == NULL)
		{
			static HMODULE s_shell32_module = NULL;
			s_shell32_module = LoadLibraryW(L"shell32.dll");
			s_shcreateitemfromparsingname = (SHCreateItemFromParsingNamePtr)GetProcAddress(s_shell32_module, "SHCreateItemFromParsingName");
		}

		IFileSaveDialog *t_file_save_dialog;
		IFileOpenDialog *t_file_open_dialog;
		IFileDialog *t_file_dialog;

		t_file_dialog = NULL;

		HRESULT t_hresult;

		if ((p_options & MCA_OPTION_SAVE_DIALOG) == 0)
		{
			t_hresult = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, __uuidof(IFileOpenDialog), (LPVOID *)&t_file_open_dialog);
			t_succeeded = SUCCEEDED(t_hresult);

			t_file_dialog = t_file_open_dialog;
		}
		else
		{
			t_hresult = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_INPROC_SERVER, __uuidof(IFileSaveDialog), (LPVOID *)&t_file_save_dialog);
			t_succeeded = SUCCEEDED(t_hresult);

			t_file_dialog = t_file_save_dialog;
		}

		if (t_succeeded)
		{
			DWORD t_options;

			t_options = FOS_FORCEFILESYSTEM | FOS_NOCHANGEDIR | FOS_PATHMUSTEXIST;
			if (p_options & MCA_OPTION_PLURAL)
				t_options |= FOS_ALLOWMULTISELECT;
			if (p_options & MCA_OPTION_SAVE_DIALOG)
				t_options |= FOS_OVERWRITEPROMPT;
			if (p_options & MCA_OPTION_FOLDER_DIALOG)
				t_options |= FOS_PICKFOLDERS;
			else
				t_options |= FOS_FILEMUSTEXIST;

			t_hresult = t_file_dialog -> SetOptions(t_options);
			t_succeeded = SUCCEEDED(t_hresult);
		}

		if (t_succeeded && *t_initial_native_folder != NULL)
		{
			IShellItem *t_initial_folder_shellitem;
			t_initial_folder_shellitem = NULL;

			MCAutoStringRefAsWString t_initial_folder_wstr;
			/* UNCHECKED */ t_initial_folder_wstr.Lock(*t_initial_native_folder);

			t_hresult = s_shcreateitemfromparsingname(*t_initial_folder_wstr, NULL, __uuidof(IShellItem), (LPVOID *)&t_initial_folder_shellitem);
			if (SUCCEEDED(t_hresult))
				t_file_dialog -> SetFolder(t_initial_folder_shellitem);
			if (t_initial_folder_shellitem != NULL)
				t_initial_folder_shellitem -> Release();
			t_succeeded = SUCCEEDED(t_hresult);
		}

		if (t_succeeded && *t_initial_file != NULL)
		{
			MCAutoStringRefAsWString t_initial_file_wstr;
			/* UNCHECKED */ t_initial_file_wstr.Lock(*t_initial_file);
			
			t_hresult = t_file_dialog -> SetFileName(*t_initial_file_wstr);
			t_succeeded = SUCCEEDED(t_hresult);
		}

		if (t_succeeded && p_filter != NULL && (p_options & MCA_OPTION_FOLDER_DIALOG) == 0)
		{
			uint4 t_filter_length, t_filter_count;
			measure_filter(p_filter, t_filter_length, t_filter_count);

			MCAutoStringRefAsWString t_filter_wstr;
			/* UNCHECKED */ t_filter_wstr.Lock(p_filter);

			COMDLG_FILTERSPEC *t_filter_spec;

			filter_to_spec(*t_filter_wstr, t_filter_count, t_filter_spec);

			t_hresult = t_file_dialog -> SetFileTypes(t_filter_count, t_filter_spec);
			t_succeeded = SUCCEEDED(t_hresult);

			delete t_filter_spec;
		}

		if (t_succeeded && p_filter != NULL && (p_options & MCA_OPTION_FOLDER_DIALOG) == 0)
		{
			t_hresult = t_file_dialog -> SetFileTypeIndex(1);
			t_succeeded = SUCCEEDED(t_hresult);
		}

		if (t_succeeded)
		{
			MCAutoStringRefAsWString t_prompt_wstr;
			/* UNCHECKED */ t_prompt_wstr.Lock(p_prompt);
			t_hresult = t_file_dialog -> SetTitle(*t_prompt_wstr);
		}

		if (t_succeeded)
		{
			t_hresult = t_file_dialog -> Show(t_window != NULL ? (HWND)t_window -> handle . window : NULL);
			t_succeeded = SUCCEEDED(t_hresult);
		}

		if ((p_options & MCA_OPTION_SAVE_DIALOG) == 0)
		{
			IShellItemArray *t_file_items;
			t_file_items = NULL;
			if (t_succeeded)
			{
				t_hresult = t_file_open_dialog -> GetResults(&t_file_items);
				t_succeeded = SUCCEEDED(t_hresult);
			}

			DWORD t_file_item_count;
			if (t_succeeded)
			{
				t_hresult = t_file_items -> GetCount(&t_file_item_count);
				t_succeeded = SUCCEEDED(t_hresult);
			}

			if (t_succeeded)
			{
				for(uint4 t_index = 0; t_index < t_file_item_count && t_succeeded; ++t_index)
				{
					IShellItem *t_file_item;
					t_file_item = NULL;
					if (t_succeeded)
					{
						t_hresult = t_file_items -> GetItemAt(t_index, &t_file_item);
						t_succeeded = SUCCEEDED(t_hresult);
					}

					if (t_succeeded)
					{
						t_hresult = append_shellitem_path_and_release(t_file_item, t_index == 0, &t_value);
						t_succeeded = SUCCEEDED(t_hresult);
					}
				}
			}

			if (t_file_items != NULL)
				t_file_items -> Release();
		}
		else
		{
			IShellItem *t_file_item;
			t_file_item = NULL;
			if (t_succeeded)
			{
				t_hresult = t_file_dialog -> GetResult(&t_file_item);
				t_succeeded = SUCCEEDED(t_hresult);
			}

			if (t_succeeded)
			{
				t_hresult = append_shellitem_path_and_release(t_file_item, true, &t_value);
				t_succeeded = SUCCEEDED(t_hresult);
			}
		}

		t_filter_index = 0;
		if (t_succeeded && (p_options & MCA_OPTION_FOLDER_DIALOG) == 0)
		{
			UINT t_index;
			t_hresult = t_file_dialog -> GetFileTypeIndex(&t_index);
			t_succeeded = SUCCEEDED(t_hresult);
			if (t_succeeded)
				t_filter_index = (int)t_index;
		}

		if (t_file_dialog != NULL)
			t_file_dialog -> Release();

		if (!t_succeeded)
			t_result = t_hresult;
		else
			t_result = 0;
	}
	else
	{
		OPENFILENAMEW t_open_dialog;
		memset(&t_open_dialog, 0, sizeof(OPENFILENAMEW));
		t_open_dialog . lStructSize = sizeof(OPENFILENAMEW);

		MCAutoStringRefAsWString t_initial_folder_wstr;
		MCAutoStringRefAsWString t_prompt_wstr;
		MCAutoStringRefAsWString t_filter_wstr;
		/* UNCHECKED */ t_filter_wstr.Lock(p_filter);
		/* UNCHECKED */ t_initial_folder_wstr.Lock(*t_initial_native_folder);
		/* UNCHECKED */ t_prompt_wstr.Lock(p_prompt);

		MCAutoArray<unichar_t> t_buffer;
		/* UNCHECKED */ t_buffer.New(MAX_PATH);

		if (!MCStringIsEmpty(*t_initial_file))
			/* UNCHECKED */ MCStringGetChars(*t_initial_file, MCRangeMake(0, t_buffer.Size()), t_buffer.Ptr());
		else
			t_buffer[0] = '\0';

		t_open_dialog . lpstrFilter = *t_filter_wstr;
		t_open_dialog . nFilterIndex = 1;
		t_open_dialog . lpstrFile = t_buffer.Ptr();
		t_open_dialog . nMaxFile = t_buffer.Size();
		t_open_dialog . lpstrInitialDir = *t_initial_folder_wstr;
		t_open_dialog . lpstrTitle = *t_prompt_wstr;
		t_open_dialog . Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR |
														OFN_LONGNAMES | OFN_PATHMUSTEXIST | OFN_EXPLORER |
														OFN_ENABLEHOOK | OFN_ENABLESIZING;

		if (p_options & MCA_OPTION_PLURAL)
			t_open_dialog . Flags |= OFN_ALLOWMULTISELECT;

		if (p_options & MCA_OPTION_SAVE_DIALOG)
			t_open_dialog . Flags |= OFN_OVERWRITEPROMPT;

		t_open_dialog . lpstrFilter = *t_filter_wstr;
		t_open_dialog . lpfnHook = open_dialog_hook;
		t_open_dialog . hwndOwner = t_window != NULL ? (HWND)t_window -> handle . window : NULL;

		if (p_options & MCA_OPTION_SAVE_DIALOG)
			t_succeeded = GetSaveFileNameW(&t_open_dialog) == TRUE;
		else
		{
			*t_open_dialog . lpstrFile = '\0';
			t_succeeded = GetOpenFileNameW(&t_open_dialog) == TRUE;
		}

		if (!t_succeeded)
			t_result = CommDlgExtendedError();

		// MW-2005-07-26: Try again without the specified filename if it was invalid
		if (t_result == FNERR_INVALIDFILENAME)
		{
			*t_open_dialog . lpstrFile = '\0';
			if (p_options & MCA_OPTION_SAVE_DIALOG)
				t_succeeded = GetSaveFileNameW(&t_open_dialog) == TRUE;
			else
				t_succeeded = GetOpenFileNameW(&t_open_dialog) == TRUE;

			if (!t_succeeded)
				t_result = CommDlgExtendedError();	
		}

		if (t_result == FNERR_BUFFERTOOSMALL)
			t_succeeded = true;

		if (t_succeeded)
		{
			build_paths(&t_value);
			t_filter_index = t_open_dialog . nFilterIndex;
		}
	}

	if (t_succeeded)
	{
		if (p_options & MCA_OPTION_RETURN_FILTER)
		{
			// The filter string has the following format:
			// "<description0>\0<extensions0>\0<description1>\0...\0<extensionsN>\0"
			// so the n'th filter comes after the 2(n - 1)'th null character
			uindex_t t_index = 2 * (t_filter_index - 1);
			uindex_t t_offset = 0;
			while (t_index--)
			{
				/* UNCHECKED */ MCStringFirstIndexOfChar(p_filter, '\0', t_offset, kMCStringOptionCompareExact, t_offset);
				t_offset++;
			}
			
			uindex_t t_end;
			t_end = UINDEX_MAX;
			/* UNCHECKED */ MCStringFirstIndexOfChar(p_filter, '\0', t_offset, kMCStringOptionCompareExact, t_end);
            
			/* UNCHECKED */ MCStringCopySubstring(p_filter, MCRangeMake(t_offset, t_end-t_offset), r_result);
		}

		t_result = 0;
		r_value = MCValueRetain(*t_value);
	}
	else
		r_result = MCValueRetain(MCNameGetString(MCN_cancel));

	waitonbutton();

	return t_result;
}