Skip to content

Commit cbe74c5

Browse files
author
Fraser J. Gordon
committed
Add basic (but not-quite-working) support for visual order field navigation
1 parent 763b806 commit cbe74c5

12 files changed

Lines changed: 223 additions & 6 deletions

engine/src/MCBlock.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class MCBlock : public MCDLlist
6565
uint2 origin;
6666
uint2 opened;
6767
uint2 tabpos; // Pixel offset to use when calculating tabstops
68+
uint2 visual_index; // Visual ordering index from left to right
6869
uint8_t direction_level;
6970

7071
// MW-2012-02-14: [[ FontRefs ]] The concrete font to use for the block.
@@ -269,6 +270,16 @@ class MCBlock : public MCDLlist
269270
origin = o;
270271
}
271272

273+
uint2 GetVisualIndex() const
274+
{
275+
return visual_index;
276+
}
277+
278+
void SetVisualIndex(uint2 i)
279+
{
280+
visual_index = i;
281+
}
282+
272283
uint2 GetDirectionLevel() const
273284
{
274285
return direction_level;
@@ -297,6 +308,10 @@ class MCBlock : public MCDLlist
297308
{
298309
tabpos = offset;
299310
}
311+
312+
// Returns the next/previous block in visual order (or nil if none)
313+
MCBlock *GetNextBlockVisualOrder();
314+
MCBlock *GetPrevBlockVisualOrder();
300315

301316
////////////////////
302317

engine/src/block.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2221,3 +2221,28 @@ codepoint_t MCBlock::GetCodepointAtIndex(findex_t p_index) const
22212221
return parent->GetCodepointAtIndex(m_index + p_index);
22222222
}
22232223

2224+
MCBlock *MCBlock::GetNextBlockVisualOrder()
2225+
{
2226+
MCBlock *bptr = this;
2227+
do
2228+
{
2229+
if (bptr->visual_index == visual_index + 1)
2230+
return bptr;
2231+
bptr = bptr->next();
2232+
} while (bptr != this);
2233+
2234+
return nil;
2235+
}
2236+
2237+
MCBlock *MCBlock::GetPrevBlockVisualOrder()
2238+
{
2239+
MCBlock *bptr = this;
2240+
do
2241+
{
2242+
if (bptr->visual_index == visual_index - 1)
2243+
return bptr;
2244+
bptr = bptr->next();
2245+
} while (bptr != this);
2246+
2247+
return nil;
2248+
}

engine/src/exec-interface-field.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,27 @@ static MCExecEnumTypeElementInfo _kMCInterfaceFieldStyleElementInfo[] =
6666
{ MCopaquestring, kMCFieldStyleShowBorder, false },
6767
};
6868

69+
static MCExecEnumTypeElementInfo _kMCInterfaceFieldCursorMovementElementInfo[] =
70+
{
71+
{ "default", kMCFieldCursorMovementDefault, false },
72+
{ "visual", kMCFieldCursorMovementVisual, false },
73+
{ "logical", kMCFieldCursorMovementLogical, false },
74+
};
75+
6976
static MCExecEnumTypeInfo _kMCInterfaceFieldStyleTypeInfo =
7077
{
7178
"Interface.FieldStyle",
7279
sizeof(_kMCInterfaceFieldStyleElementInfo) / sizeof(MCExecEnumTypeElementInfo),
7380
_kMCInterfaceFieldStyleElementInfo
7481
};
7582

83+
static MCExecEnumTypeInfo _kMCInterfaceFieldCursorMovementTypeInfo =
84+
{
85+
"Interface.CursorMovement",
86+
sizeof(_kMCInterfaceFieldCursorMovementElementInfo) / sizeof(MCExecEnumTypeElementInfo),
87+
_kMCInterfaceFieldCursorMovementElementInfo
88+
};
89+
7690
//////////
7791

7892
static void MCInterfaceFlaggedRangesParse(MCExecContext& ctxt, MCStringRef p_input, MCInterfaceFlaggedRanges& r_output)
@@ -191,6 +205,7 @@ static MCExecEnumTypeInfo _kMCInterfaceLayerModeTypeInfo =
191205

192206
MCExecEnumTypeInfo *kMCInterfaceFieldStyleTypeInfo = &_kMCInterfaceFieldStyleTypeInfo;
193207
MCExecCustomTypeInfo *kMCInterfaceFlaggedRangesTypeInfo = &_kMCInterfaceFlaggedRangesTypeInfo;
208+
MCExecEnumTypeInfo *kMCInterfaceFieldCursorMovementTypeInfo = &_kMCInterfaceFieldCursorMovementTypeInfo;
194209

195210
////////////////////////////////////////////////////////////////////////////////
196211

@@ -881,6 +896,16 @@ void MCField::GetEncoding(MCExecContext& ctxt, uint32_t part, intenum_t& r_encod
881896
r_encoding = t_encoding;
882897
}
883898

899+
void MCField::SetCursorMovement(MCExecContext& ctxt, intenum_t p_movement)
900+
{
901+
cursor_movement = (MCInterfaceFieldCursorMovement)p_movement;
902+
}
903+
904+
void MCField::GetCursorMovement(MCExecContext& ctxt, intenum_t &r_movement)
905+
{
906+
r_movement = intenum_t(cursor_movement);
907+
}
908+
884909
////////////////////////////////////////////////////////////////////////////////////////
885910

886911
void MCField::GetHilitedLines(MCExecContext& ctxt, uindex_t& r_count, uinteger_t*& r_lines)

engine/src/exec-interface-object.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ static PropList fieldprops[] =
254254
{"borderWidth", P_BORDER_WIDTH},
255255
{"cantSelect", P_CANT_SELECT},
256256
{"colors", P_COLORS},
257+
{"cursorMovement", P_CURSORMOVEMENT},
257258
{"disabled", P_DISABLED},
258259
{"dontSearch", P_DONT_SEARCH},
259260
{"dontWrap", P_DONT_WRAP},

engine/src/exec.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3284,6 +3284,7 @@ extern MCExecSetTypeInfo *kMCInterfaceButtonAcceleratorModifiersTypeInfo;
32843284

32853285
extern MCExecEnumTypeInfo *kMCInterfaceFieldStyleTypeInfo;
32863286
extern MCExecCustomTypeInfo *kMCInterfaceFlaggedRangesTypeInfo;
3287+
extern MCExecEnumTypeInfo *kMCInterfaceFieldCursorMovementTypeInfo;
32873288

32883289
///////////
32893290

engine/src/field.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ MCPropertyInfo MCField::kProperties[] =
100100
DEFINE_RW_OBJ_PROPERTY(P_LIST_BEHAVIOR, Bool, MCField, ListBehavior)
101101
DEFINE_RW_OBJ_PROPERTY(P_MULTIPLE_HILITES, Bool, MCField, MultipleHilites)
102102
DEFINE_RW_OBJ_PROPERTY(P_NONCONTIGUOUS_HILITES, Bool, MCField, NoncontiguousHilites)
103+
DEFINE_RW_OBJ_ENUM_PROPERTY(P_CURSORMOVEMENT, InterfaceFieldCursorMovement, MCField, CursorMovement)
103104
DEFINE_RW_OBJ_PART_PROPERTY(P_TEXT, String, MCField, Text)
104105
DEFINE_RW_OBJ_PART_PROPERTY(P_UNICODE_TEXT, BinaryString, MCField, UnicodeText)
105106
DEFINE_RW_OBJ_PART_NON_EFFECTIVE_PROPERTY(P_HTML_TEXT, Any, MCField, HtmlText)
@@ -3341,3 +3342,21 @@ bool MCField::imagechanged(MCImage *p_image, bool p_deleting)
33413342

33423343
return t_used;
33433344
}
3345+
3346+
///////////////////////////////////////////////////////////////////////////////
3347+
3348+
bool MCField::IsCursorMovementVisual()
3349+
{
3350+
if (cursor_movement == kMCFieldCursorMovementLogical)
3351+
return false;
3352+
else if (cursor_movement == kMCFieldCursorMovementVisual)
3353+
return true;
3354+
else
3355+
{
3356+
#ifdef __WIN32
3357+
return false;
3358+
#else
3359+
return true;
3360+
#endif
3361+
}
3362+
}

engine/src/field.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ enum
130130
kMCFieldExportFlattenStyles = 1 << 6,
131131
};
132132

133+
enum MCInterfaceFieldCursorMovement
134+
{
135+
kMCFieldCursorMovementDefault,
136+
kMCFieldCursorMovementVisual,
137+
kMCFieldCursorMovementLogical,
138+
};
139+
133140
// MW-2012-02-20: [[ FieldExport ]] The event that occured to cause the callback.
134141
enum MCFieldExportEventType
135142
{
@@ -223,6 +230,7 @@ class MCField : public MCControl
223230
MCScrollbar *hscrollbar;
224231
MCStringRef label;
225232
MCFieldTextDirection text_direction;
233+
MCInterfaceFieldCursorMovement cursor_movement;
226234

227235
static int2 clickx;
228236
static int2 clicky;
@@ -640,6 +648,7 @@ class MCField : public MCControl
640648
////////// BIDIRECTIONAL SUPPORT
641649

642650
MCFieldTextDirection getbasetextdirection() { return text_direction; }
651+
bool IsCursorMovementVisual();
643652

644653
////////// PROPERTY SUPPORT METHODS
645654

@@ -726,6 +735,8 @@ class MCField : public MCControl
726735
void GetThreeDHilite(MCExecContext& ctxt, bool& r_setting);
727736
void SetThreeDHilite(MCExecContext& ctxt, bool setting);
728737
void GetEncoding(MCExecContext& ctxt, uint32_t part, intenum_t& r_encoding);
738+
void SetCursorMovement(MCExecContext&, intenum_t);
739+
void GetCursorMovement(MCExecContext&, intenum_t&);
729740

730741
void GetHilitedLines(MCExecContext& ctxt, uindex_t& r_count, uinteger_t*& r_lines);
731742
void SetHilitedLines(MCExecContext& ctxt, uindex_t p_count, uinteger_t* p_lines);

engine/src/line.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ void MCLine::ResolveDisplayOrder()
542542
bptr = t_visual_order[i];
543543
setscents(bptr);
544544
bptr -> setorigin(width);
545+
bptr -> SetVisualIndex(i);
545546
width += bptr -> getwidth(NULL);
546547
}
547548

engine/src/objdefs.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -683,15 +683,15 @@ enum Field_translations {
683683
FT_PARAGRAPH,
684684
FT_PARAGRAPHAFTER,
685685
FT_LEFTCHAR,
686-
FT_BACKCHAR = FT_LEFTCHAR,
686+
FT_BACKCHAR,
687687
FT_LEFTWORD,
688-
FT_BACKWORD = FT_LEFTWORD,
688+
FT_BACKWORD,
689689
FT_LEFTPARA,
690690
FT_BACKPARA = FT_LEFTPARA,
691691
FT_RIGHTCHAR,
692-
FT_FORWARDCHAR = FT_RIGHTCHAR,
692+
FT_FORWARDCHAR,
693693
FT_RIGHTWORD,
694-
FT_FORWARDWORD = FT_RIGHTWORD,
694+
FT_FORWARDWORD,
695695
FT_RIGHTPARA,
696696
FT_FORWARDPARA = FT_RIGHTPARA,
697697
FT_UP,

engine/src/paragraf.cpp

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2483,8 +2483,123 @@ int2 MCParagraph::fdelete(Field_translations type, MCParagraph *&undopgptr)
24832483
return 0;
24842484
}
24852485

2486-
uint1 MCParagraph::fmovefocus(Field_translations type)
2486+
uint1 MCParagraph::fmovefocus_visual(Field_translations type)
24872487
{
2488+
// Get the current block and its text direction
2489+
MCBlock *sbptr = indextoblock(focusedindex, false);
2490+
bool t_is_rtl = sbptr->is_rtl();
2491+
2492+
// Attempt to move non-visually and then back-out if we crossed a text
2493+
// direction boundary (as this is where visual order matters)
2494+
findex_t t_original_index = focusedindex;
2495+
Field_translations t_logical_type;
2496+
bool t_direction_matters = true;
2497+
switch (type)
2498+
{
2499+
case FT_LEFTCHAR:
2500+
t_logical_type = t_is_rtl ? FT_FORWARDCHAR : FT_BACKCHAR;
2501+
break;
2502+
2503+
case FT_LEFTWORD:
2504+
t_logical_type = t_is_rtl ? FT_FORWARDWORD : FT_BACKWORD;
2505+
break;
2506+
2507+
case FT_RIGHTCHAR:
2508+
t_logical_type = t_is_rtl ? FT_BACKCHAR : FT_FORWARDCHAR;
2509+
break;
2510+
2511+
case FT_RIGHTWORD:
2512+
t_logical_type = t_is_rtl ? FT_BACKWORD : FT_FORWARDWORD;
2513+
break;
2514+
2515+
default:
2516+
t_logical_type = type;
2517+
t_direction_matters = false;
2518+
break;
2519+
}
2520+
2521+
uint1 t_result = fmovefocus(t_logical_type, true);
2522+
if (!t_direction_matters || t_result != FT_UNDEFINED)
2523+
return t_result;
2524+
2525+
// Blocks may have been crossed. Did we cross any directional boundaries?
2526+
bool t_direction_changed = false;
2527+
MCBlock *bptr = sbptr;
2528+
MCBlock *ebptr = indextoblock(focusedindex, false);
2529+
while (bptr != ebptr)
2530+
{
2531+
if (bptr->is_rtl() != t_is_rtl)
2532+
{
2533+
t_direction_changed = true;
2534+
break;
2535+
}
2536+
bptr = bptr->next();
2537+
}
2538+
2539+
// If no directional boundaries were crossed, nothing needs to be done
2540+
if (!t_direction_changed)
2541+
return t_result;
2542+
2543+
// Block boundary was crossed. We will decree that changing text direction
2544+
// always ends a word or character (not doing so would seem a bit odd).
2545+
MCBlock *tbptr;
2546+
if (type == FT_LEFTCHAR || type == FT_LEFTWORD)
2547+
{
2548+
tbptr = sbptr->GetPrevBlockVisualOrder();
2549+
2550+
// Position cursor at the beginning/end of this block, as appropriate
2551+
if (tbptr == nil)
2552+
return FT_LEFTCHAR;
2553+
else if (tbptr->is_rtl())
2554+
focusedindex = tbptr->GetOffset() + tbptr->GetLength();
2555+
else
2556+
focusedindex = tbptr->GetOffset();
2557+
}
2558+
else // type == FT_RIGHTCHAR || type == FT_RIGHTWORD
2559+
{
2560+
tbptr = sbptr->GetNextBlockVisualOrder();
2561+
2562+
// Position cursor at the beginning/end of this block, as appropriate
2563+
if (tbptr == nil)
2564+
return FT_RIGHTCHAR;
2565+
if (tbptr->is_rtl())
2566+
focusedindex = tbptr->GetOffset();
2567+
else
2568+
focusedindex = tbptr->GetOffset() + tbptr->GetLength();
2569+
}
2570+
2571+
// All done
2572+
return FT_UNDEFINED;
2573+
}
2574+
2575+
uint1 MCParagraph::fmovefocus(Field_translations type, bool p_force_logical)
2576+
{
2577+
// Get the cursor movement style of the parent field
2578+
bool t_visual_movement;
2579+
t_visual_movement = parent->IsCursorMovementVisual();
2580+
if (!p_force_logical && t_visual_movement)
2581+
return fmovefocus_visual(type);
2582+
2583+
// Using logical ordering so translate the type
2584+
switch (type)
2585+
{
2586+
case FT_LEFTCHAR:
2587+
type = FT_BACKCHAR;
2588+
break;
2589+
2590+
case FT_LEFTWORD:
2591+
type = FT_BACKWORD;
2592+
break;
2593+
2594+
case FT_RIGHTCHAR:
2595+
type = FT_FORWARDCHAR;
2596+
break;
2597+
2598+
case FT_RIGHTWORD:
2599+
type = FT_FORWARDWORD;
2600+
break;
2601+
}
2602+
24882603
findex_t oldfocused = focusedindex;
24892604
uindex_t t_length = gettextlength();
24902605
switch (type)

0 commit comments

Comments
 (0)