Images support inside table cells
This commit is contained in:
parent
b497f872e5
commit
bc38768539
@ -5,6 +5,7 @@
|
||||
* `TextLayoutSpan` to obtain `Layout` in which markdown is displayed (applied by `TablePlugin`, more specifically `TableRowSpan` to propagate layout in which cell content is displayed)
|
||||
* `HtmlEmptyTagReplacement` now is configurable by `HtmlPlugin`, `iframe` handling ([#235])
|
||||
* `AsyncDrawableLoader` now uses `TextView` width without padding instead of width of canvas
|
||||
* Support for images inside table cells (`ext-tables` module)
|
||||
|
||||
[#235]: https://github.com/noties/Markwon/issues/235
|
||||
|
||||
|
@ -530,7 +530,20 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
|
||||
@NonNull
|
||||
@Override
|
||||
public Rect resolveImageSize(@NonNull AsyncDrawable drawable) {
|
||||
return drawable.getResult().getBounds();
|
||||
|
||||
// @since $nap; resolve inline size (scale down if exceed available width)
|
||||
final Rect imageBounds = drawable.getResult().getBounds();
|
||||
final int canvasWidth = drawable.getLastKnownCanvasWidth();
|
||||
final int w = imageBounds.width();
|
||||
|
||||
if (w > canvasWidth) {
|
||||
// here we must scale it down (keeping the ratio)
|
||||
final float ratio = (float) w / imageBounds.height();
|
||||
final int h = (int) (canvasWidth / ratio + .5F);
|
||||
return new Rect(0, 0, canvasWidth, h);
|
||||
}
|
||||
|
||||
return imageBounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Layout;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
@ -23,6 +24,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.noties.markwon.core.spans.TextLayoutSpan;
|
||||
import io.noties.markwon.image.AsyncDrawable;
|
||||
import io.noties.markwon.image.AsyncDrawableSpan;
|
||||
import io.noties.markwon.utils.LeadingMarginUtils;
|
||||
import io.noties.markwon.utils.SpanUtils;
|
||||
|
||||
@ -71,7 +74,7 @@ public class TableRowSpan extends ReplacementSpan {
|
||||
|
||||
private final TableTheme theme;
|
||||
private final List<Cell> cells;
|
||||
private final List<StaticLayout> layouts;
|
||||
private final List<Layout> layouts;
|
||||
private final TextPaint textPaint;
|
||||
private final boolean header;
|
||||
private final boolean odd;
|
||||
@ -112,7 +115,7 @@ public class TableRowSpan extends ReplacementSpan {
|
||||
if (fm != null) {
|
||||
|
||||
int max = 0;
|
||||
for (StaticLayout layout : layouts) {
|
||||
for (Layout layout : layouts) {
|
||||
final int height = layout.getHeight();
|
||||
if (height > max) {
|
||||
max = height;
|
||||
@ -240,7 +243,7 @@ public class TableRowSpan extends ReplacementSpan {
|
||||
final int borderTop = isFirstTableRow ? borderWidth : 0;
|
||||
final int borderBottom = bottom - top - borderWidth;
|
||||
|
||||
StaticLayout layout;
|
||||
Layout layout;
|
||||
for (int i = 0; i < size; i++) {
|
||||
layout = layouts.get(i);
|
||||
final int save = canvas.save();
|
||||
@ -297,13 +300,27 @@ public class TableRowSpan extends ReplacementSpan {
|
||||
final int w = (width / columns) - padding;
|
||||
|
||||
this.layouts.clear();
|
||||
Cell cell;
|
||||
StaticLayout layout;
|
||||
Spannable spannable;
|
||||
|
||||
for (int i = 0, size = cells.size(); i < size; i++) {
|
||||
makeLayout(i, w, cells.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
cell = cells.get(i);
|
||||
private void makeLayout(final int index, final int width, @NonNull final Cell cell) {
|
||||
|
||||
final Runnable recreate = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Invalidator invalidator = TableRowSpan.this.invalidator;
|
||||
if (invalidator != null) {
|
||||
layouts.remove(index);
|
||||
makeLayout(index, width, cell);
|
||||
invalidator.invalidate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final Spannable spannable;
|
||||
|
||||
if (cell.text instanceof Spannable) {
|
||||
spannable = (Spannable) cell.text;
|
||||
@ -311,10 +328,10 @@ public class TableRowSpan extends ReplacementSpan {
|
||||
spannable = new SpannableString(cell.text);
|
||||
}
|
||||
|
||||
layout = new StaticLayout(
|
||||
final Layout layout = new StaticLayout(
|
||||
spannable,
|
||||
textPaint,
|
||||
w,
|
||||
width,
|
||||
alignment(cell.alignment),
|
||||
1.0F,
|
||||
0.0F,
|
||||
@ -324,7 +341,35 @@ public class TableRowSpan extends ReplacementSpan {
|
||||
// @since $nap;
|
||||
TextLayoutSpan.applyTo(spannable, layout);
|
||||
|
||||
layouts.add(layout);
|
||||
// @since $nap;
|
||||
scheduleAsyncDrawables(spannable, recreate);
|
||||
|
||||
layouts.add(index, layout);
|
||||
}
|
||||
|
||||
private void scheduleAsyncDrawables(@NonNull Spannable spannable, @NonNull final Runnable recreate) {
|
||||
|
||||
final AsyncDrawableSpan[] spans = spannable.getSpans(0, spannable.length(), AsyncDrawableSpan.class);
|
||||
if (spans != null
|
||||
&& spans.length > 0) {
|
||||
|
||||
for (AsyncDrawableSpan span : spans) {
|
||||
|
||||
final AsyncDrawable drawable = span.getDrawable();
|
||||
|
||||
// it is absolutely crucial to check if drawable is already attached,
|
||||
// otherwise we would end up with a loop
|
||||
if (drawable.isAttached()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
drawable.setCallback2(new CallbackAdapter() {
|
||||
@Override
|
||||
public void invalidateDrawable(@NonNull Drawable who) {
|
||||
recreate.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -348,4 +393,21 @@ public class TableRowSpan extends ReplacementSpan {
|
||||
public void invalidator(@Nullable Invalidator invalidator) {
|
||||
this.invalidator = invalidator;
|
||||
}
|
||||
|
||||
private static abstract class CallbackAdapter implements Drawable.Callback {
|
||||
@Override
|
||||
public void invalidateDrawable(@NonNull Drawable who) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,8 @@ public class LatexActivity extends ActivityWithMenuOptions {
|
||||
.add("textColor", this::textColor)
|
||||
.add("defaultTextColor", this::defaultTextColor)
|
||||
.add("inlineAndBlock", this::inlineAndBlock)
|
||||
.add("dark", this::dark);
|
||||
.add("dark", this::dark)
|
||||
.add("omega", this::omega);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -221,6 +222,18 @@ public class LatexActivity extends ActivityWithMenuOptions {
|
||||
renderWithBlocksAndInlines(md);
|
||||
}
|
||||
|
||||
private void omega() {
|
||||
final String md = "" +
|
||||
"# Block\n\n" +
|
||||
"$$\n" +
|
||||
"\\Omega\n" +
|
||||
"$$\n\n" +
|
||||
"# Inline\n\n" +
|
||||
"$$\\Omega$$";
|
||||
|
||||
renderWithBlocksAndInlines(md);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String wrapLatexInSampleMarkdown(@NonNull String latex) {
|
||||
return "" +
|
||||
|
@ -7,10 +7,11 @@ import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import io.noties.debug.Debug;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.ext.latex.JLatexMathPlugin;
|
||||
import io.noties.markwon.ext.tables.TablePlugin;
|
||||
import io.noties.markwon.ext.tables.TableTheme;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.linkify.LinkifyPlugin;
|
||||
import io.noties.markwon.sample.ActivityWithMenuOptions;
|
||||
import io.noties.markwon.sample.MenuOptions;
|
||||
@ -25,7 +26,9 @@ public class TableActivity extends ActivityWithMenuOptions {
|
||||
public MenuOptions menuOptions() {
|
||||
return MenuOptions.create()
|
||||
.add("customize", this::customize)
|
||||
.add("tableAndLinkify", this::tableAndLinkify);
|
||||
.add("tableAndLinkify", this::tableAndLinkify)
|
||||
.add("withImages", this::withImages)
|
||||
.add("withLatex", this::withLatex);
|
||||
}
|
||||
|
||||
private TextView textView;
|
||||
@ -86,4 +89,47 @@ public class TableActivity extends ActivityWithMenuOptions {
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
|
||||
private void withImages() {
|
||||
|
||||
final String md = "" +
|
||||
"| HEADER | HEADER |\n" +
|
||||
"|:----:|:----:|\n" +
|
||||
"|  | Build |\n" +
|
||||
"| Stable |  |\n" +
|
||||
"| BIG |  |\n" +
|
||||
"\n";
|
||||
|
||||
final Markwon markwon = Markwon.builder(this)
|
||||
.usePlugin(ImagesPlugin.create())
|
||||
.usePlugin(TablePlugin.create(this))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
|
||||
private void withLatex() {
|
||||
|
||||
String latex = "\\begin{array}{cc}";
|
||||
latex += "\\fbox{\\text{A framed box with \\textdbend}}&\\shadowbox{\\text{A shadowed box}}\\cr";
|
||||
latex += "\\doublebox{\\text{A double framed box}}&\\ovalbox{\\text{An oval framed box}}\\cr";
|
||||
latex += "\\end{array}";
|
||||
|
||||
final String md = "" +
|
||||
"| HEADER | HEADER |\n" +
|
||||
"|:----:|:----:|\n" +
|
||||
"|  | Build |\n" +
|
||||
"| Stable |  |\n" +
|
||||
"| BIG | $$" + latex + "$$ |\n" +
|
||||
"\n";
|
||||
|
||||
final Markwon markwon = Markwon.builder(this)
|
||||
.usePlugin(MarkwonInlineParserPlugin.create())
|
||||
.usePlugin(ImagesPlugin.create())
|
||||
.usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> builder.inlinesEnabled(true)))
|
||||
.usePlugin(TablePlugin.create(this))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user