///|
fn append_text_field_selection_commands(
commands : Array[DrawCommand],
text_frame : Rect,
layout : TextLayoutResult,
selection : TextRange?,
) -> Unit {
match active_text_selection(selection) {
Some(selection) => {
let start = clamp_int(
selection.start,
0,
layout.caret_positions.length() - 1,
)
let end = clamp_int(
selection.end,
start,
layout.caret_positions.length() - 1,
)
let x0 = text_frame.origin.x + layout.caret_positions[start]
let x1 = text_frame.origin.x + layout.caret_positions[end]
if x1 > x0 {
commands.push(
FillRect(
Rect::new(
x=x0,
y=text_frame.origin.y + 6.0,
width=x1 - x0,
height=max_double(8.0, text_frame.size.height - 12.0),
),
Color::blue().with_alpha(0.18),
),
)
}
}
None => ()
}
}
///|
fn append_searchbar_search_icon(
commands : Array[DrawCommand],
frame : Rect,
color : Color,
) -> Unit {
let center = Point::new(
x=frame.origin.x + frame.size.width * 0.42,
y=frame.origin.y + frame.size.height * 0.42,
)
let radius = frame.size.width * 0.26
commands.push(
StrokeRoundedRect(
RoundedRect::new(
rect=Rect::new(
x=center.x - radius,
y=center.y - radius,
width=radius * 2.0,
height=radius * 2.0,
),
radius~,
),
color,
1.6,
),
)
commands.push(
DrawPath(
PathSpec::new(
verbs=[
PathVerb::MoveTo(
Point::new(x=center.x + radius * 0.7, y=center.y + radius * 0.7),
),
PathVerb::LineTo(
Point::new(
x=frame.origin.x + frame.size.width * 0.86,
y=frame.origin.y + frame.size.height * 0.86,
),
),
],
stroke=Some(Brush::solid(color)),
stroke_width=1.6,
),
),
)
}
///|
fn append_searchbar_clear_icon(
commands : Array[DrawCommand],
frame : Rect,
color : Color,
) -> Unit {
let inset = frame.size.width * 0.28
commands.push(
DrawPath(
PathSpec::new(
verbs=[
PathVerb::MoveTo(
Point::new(x=frame.origin.x + inset, y=frame.origin.y + inset),
),
PathVerb::LineTo(
Point::new(
x=frame.origin.x + frame.size.width - inset,
y=frame.origin.y + frame.size.height - inset,
),
),
PathVerb::MoveTo(
Point::new(
x=frame.origin.x + frame.size.width - inset,
y=frame.origin.y + inset,
),
),
PathVerb::LineTo(
Point::new(
x=frame.origin.x + inset,
y=frame.origin.y + frame.size.height - inset,
),
),
],
stroke=Some(Brush::solid(color)),
stroke_width=1.6,
),
),
)
}
///|
fn append_text_field_commands(
commands : Array[DrawCommand],
element : ElementNode,
data : TextFieldViewSpec,
frame : Rect,
focused : Bool,
environment : RenderEnvironment,
) -> Unit {
let border = if focused { data.focused_border } else { data.border }
let rounded = RoundedRect::new(rect=frame, radius=data.corner_radius)
if data.corner_radius > 0.0 {
commands.push(FillRoundedRectBrush(rounded, data.background))
} else {
commands.push(FillRoundedRectBrush(rounded, data.background))
}
match border {
Some(border) =>
if border.width > 0.0 {
commands.push(
StrokeRoundedRectBrush(rounded, border.brush, border.width),
)
}
None => ()
}
let text = data.value.get()
let display_text = text_with_composition(text, element, focused)
let display = if display_text == "" { data.placeholder } else { display_text }
let font = environment_font(environment, data.font)
let color = if text == "" {
environment_color(environment, data.placeholder_color)
} else {
environment_color(environment, data.foreground)
}
let text_frame = frame.inset(Insets::symmetric(horizontal=10.0, vertical=4.0))
if focused && element.control.composition is None {
let layout = environment_measure_text(
environment,
TextLayoutInput::new(
text=display_text,
font~,
max_width=text_frame.size.width,
),
)
append_text_field_selection_commands(
commands,
text_frame,
layout,
element.control.selection,
)
}
commands.push(
DrawText(
TextRun::new(
text=display,
frame=text_frame,
font~,
color~,
align=TextAlign::TextStart,
),
),
)
if focused {
let layout = environment_measure_text(
environment,
TextLayoutInput::new(
text=display_text,
font~,
max_width=text_frame.size.width,
),
)
let caret = clamp_int(
text_field_visual_caret(text, element, focused),
0,
layout.caret_positions.length() - 1,
)
let cursor_x = text_frame.origin.x + layout.caret_positions[caret]
let cursor = Rect::new(
x=cursor_x,
y=text_frame.origin.y + 6.0,
width=1.5,
height=max_double(8.0, text_frame.size.height - 12.0),
)
commands.push(FillRect(cursor, data.cursor_color))
}
}
///|
fn append_searchbar_commands(
commands : Array[DrawCommand],
element : ElementNode,
data : SearchBarViewSpec,
frame : Rect,
environment : RenderEnvironment,
focused_id : ElementId?,
) -> Unit {
let rounded = RoundedRect::new(rect=frame, radius=data.corner_radius)
let is_focused = focused_id == Some(element.id)
let border = if is_focused { data.focused_border } else { data.border }
commands.push(FillRoundedRectBrush(rounded, data.background))
match border {
Some(border) =>
if border.width > 0.0 {
commands.push(
StrokeRoundedRectBrush(rounded, border.brush, border.width),
)
}
None => ()
}
let icon_frame = Rect::new(
x=frame.origin.x + 10.0,
y=frame.origin.y + (frame.size.height - 16.0) / 2.0,
width=16.0,
height=16.0,
)
append_searchbar_search_icon(
commands,
icon_frame,
data.foreground.with_alpha(0.6),
)
let text = data.query.get()
let display_text = text_with_composition(text, element, is_focused)
let display = if display_text == "" { data.placeholder } else { display_text }
let font = environment_font(environment, data.font)
let color = if text == "" {
environment_color(environment, data.placeholder_color)
} else {
environment_color(environment, data.foreground)
}
let text_frame = Rect::new(
x=frame.origin.x + 32.0,
y=frame.origin.y,
width=if text != "" {
frame.size.width - 64.0
} else {
frame.size.width - 32.0
},
height=frame.size.height,
).inset(Insets::symmetric(vertical=0.0))
if is_focused && element.control.composition is None {
let layout = environment_measure_text(
environment,
TextLayoutInput::new(
text=display_text,
font~,
max_width=text_frame.size.width,
),
)
append_text_field_selection_commands(
commands,
text_frame,
layout,
element.control.selection,
)
}
commands.push(
DrawText(
TextRun::new(
text=display,
frame=text_frame,
font~,
color~,
align=TextAlign::TextStart,
),
),
)
if is_focused {
let layout = environment_measure_text(
environment,
TextLayoutInput::new(
text=display_text,
font~,
max_width=text_frame.size.width,
),
)
let caret = clamp_int(
text_field_visual_caret(text, element, is_focused),
0,
layout.caret_positions.length() - 1,
)
let cursor_x = text_frame.origin.x + layout.caret_positions[caret]
let cursor = Rect::new(
x=cursor_x,
y=text_frame.origin.y + 6.0,
width=1.5,
height=max_double(8.0, text_frame.size.height - 12.0),
)
commands.push(FillRect(cursor, data.cursor_color))
}
if text != "" {
let clear_frame = Rect::new(
x=frame.origin.x + frame.size.width - 26.0,
y=frame.origin.y + (frame.size.height - 16.0) / 2.0,
width=16.0,
height=16.0,
)
append_searchbar_clear_icon(
commands,
clear_frame,
data.foreground.with_alpha(0.6),
)
}
}