/*
* Copyright (C) 2015-2017 Emanuel Moecklin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.onegravity.rteditor.spans;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.text.Layout;
import android.text.Spanned;
import android.text.style.LeadingMarginSpan;
/**
* Implementation for a bullet point LeadingMarginSpan
* <p>
* Android seems to add the leading margin for an empty paragraph to the
* previous paragraph (]0, 4][4, 4] --> the leading margin of the second span is
* added to the ]0, 4] paragraph regardless of the Spanned.flags) --> therefore
* we ignore the leading margin for the last, empty paragraph unless it's the
* only one
*/
public class BulletSpan implements LeadingMarginSpan, RTSpan<Boolean>, RTParagraphSpan<Boolean> {
private static Path sBulletPath = null;
private final int mGapWidth;
private final boolean mIgnoreSpan;
public BulletSpan(int gapWidth, boolean isEmpty, boolean isFirst, boolean isLast) {
mGapWidth = gapWidth;
mIgnoreSpan = isEmpty && isLast && !isFirst;
if (sBulletPath == null) {
sBulletPath = new Path();
}
}
private BulletSpan(int gapWidth, boolean ignoreSpan) {
mGapWidth = gapWidth;
mIgnoreSpan = ignoreSpan;
}
@Override
public int getLeadingMargin(boolean first) {
return mIgnoreSpan ? 0 : mGapWidth;
}
@Override
public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom,
CharSequence text, int start, int end, boolean first, Layout l) {
Spanned spanned = (Spanned) text;
if (!mIgnoreSpan && spanned.getSpanStart(this) == start) {
// set paint
Paint.Style oldStyle = p.getStyle();
p.setStyle(Paint.Style.FILL);
// draw the bullet point
int size = Math.max(Math.round((baseline - top) / 9f), 4);
draw(c, p, x, dir, top, bottom, size);
// restore paint
p.setStyle(oldStyle);
}
}
private void draw(Canvas c, Paint p, int x, int dir, int top, int bottom, int size) {
sBulletPath.reset();
sBulletPath.addCircle(0.0f, 0.0f, size, Direction.CW);
c.save();
c.translate(x + dir * size, (top + bottom) / 2.0f);
c.drawPath(sBulletPath, p);
c.restore();
}
@Override
public Boolean getValue() {
return Boolean.TRUE;
}
@Override
public BulletSpan createClone() {
return new BulletSpan(mGapWidth, mIgnoreSpan);
}
}