From dacd1a12da5c1c28c60b2806b371f6c577b0604f Mon Sep 17 00:00:00 2001 From: Marcus Lundblad Date: Sun, 17 Mar 2019 22:22:29 +0100 Subject: transitPrintLayout: Use Cairo and Pango to render Fixes #78 --- src/transitPrintLayout.js | 134 +++++++++++++++++++++++++++++++--------------- 1 file changed, 90 insertions(+), 44 deletions(-) diff --git a/src/transitPrintLayout.js b/src/transitPrintLayout.js index 5648390d..323ed1e7 100644 --- a/src/transitPrintLayout.js +++ b/src/transitPrintLayout.js @@ -22,16 +22,16 @@ const Cairo = imports.cairo; const Champlain = imports.gi.Champlain; const Clutter = imports.gi.Clutter; -const Gdk = imports.gi.Gdk; const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; +const Pango = imports.gi.Pango; +const Color = imports.color; +const Gfx = imports.gfx; const MapSource = imports.mapSource; const PrintLayout = imports.printLayout; +const Transit = imports.transit; const TransitArrivalMarker = imports.transitArrivalMarker; -const TransitArrivalRow = imports.transitArrivalRow; const TransitBoardMarker = imports.transitBoardMarker; -const TransitLegRow = imports.transitLegRow; const TransitWalkMarker = imports.transitWalkMarker; // stroke color for walking paths @@ -59,6 +59,9 @@ const _Instruction = { SCALE_MARGIN: 0.01 }; +// luminance threashhold for drawing outline around route label badges +const OUTLINE_LUMINANCE_THREASHHOLD = 0.9; + var TransitPrintLayout = GObject.registerClass( class TransitPrintLayout extends PrintLayout.PrintLayout { @@ -184,54 +187,97 @@ class TransitPrintLayout extends PrintLayout.PrintLayout { } } - _renderWidget(widget, width, height) { + _drawInstruction(width, height, leg, start) { let pageNum = this.numPages - 1; let x = this._cursorX; let y = this._cursorY; + let surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, width, height); + let cr = new Cairo.Context(surface); + let timeWidth = !leg.transit && start ? height : height * 2; + let fromText = Transit.getFromLabel(leg, start); + let routeWidth = 0; + + this._drawIcon(cr, leg.iconName, width, height); + this._drawText(cr, fromText, this._rtl ? timeWidth : height, 0, + width - height - timeWidth, height / 2, Pango.Alignment.LEFT); + + if (leg.transit) { + let color = leg.color; + let textColor = leg.textColor; + let hasOutline = Color.relativeLuminance(color) > OUTLINE_LUMINANCE_THREASHHOLD; + let routeText = + this._createTextLayout(cr, leg.route, width - height - timeWidth, + height / 2, + this._rtl ? Pango.Alignment.RIGHT : + Pango.Alignment.LEFT); + let [pWidth, pHeight] = routeText.get_pixel_size(); + let routePadding = 3; + let routeHeight = pHeight + routePadding * 2; + routeWidth = Math.max(pWidth, pHeight) + routePadding * 2; + let routeX = this._rtl ? width - height - routeWidth - 1 : height; + let routeY = height / 2 + ((height / 2) - routeHeight) / 2; + + + textColor = Color.getContrastingForegroundColor(color, textColor); + Gfx.drawColoredBagde(cr, color, hasOutline ? textColor : null, + routeX, routeY, routeWidth, routeHeight); + this._drawTextLayoutWithColor(cr, routeText, + routeX + routePadding + + (routeWidth - pWidth - + routePadding * 2) / 2, + routeY + routePadding, + routeWidth - routePadding * 2, + routeHeight - routePadding * 2, + textColor, Pango.Alignment.LEFT); + + // introduce some additional padding before the headsign label + routeWidth += routePadding; + } - let offscreenWindow = new Gtk.OffscreenWindow({ visible: true }); - - widget.width_request = width; - widget.height_request = height; - - widget.get_style_context().add_class('printing-text'); - - // Paint the background of the row to be transparent - widget.connect('draw', (widget, cr) => { - cr.setSourceRGBA(0.0, 0.0, 0.0, 0.0); - cr.setOperator(Cairo.Operator.SOURCE); - cr.paint(); - cr.setOperator(Cairo.Operator.OVER); - }); - - widget.queue_draw(); - offscreenWindow.add(widget); - offscreenWindow.set_valign(Gtk.Align.START); - offscreenWindow.connect('damage-event', (widget) => { - let surface = widget.get_surface(); - this._addSurface(surface, x, y, pageNum); - }); - } + let headsign = Transit.getHeadsignLabel(leg); + + if (headsign) { + let headsignLayout = this._createTextLayout(cr, headsign, + width - height - timeWidth - routeWidth, + height / 2, + Pango.Alignment.LEFT); + let [pWidth, pHeight] = headsignLayout.get_pixel_size(); + this._drawTextLayoutWithColor(cr, headsignLayout, + this._rtl ? timeWidth : height + routeWidth, + height / 2 + (height / 2 - pHeight) / 2, + width - height - timeWidth - routeWidth, + height / 2, '888888', + Pango.Alignment.LEFT); + } + this._drawTextVerticallyCentered(cr, leg.prettyPrintTime({ isStart: start }), + timeWidth, height, + this._rtl ? 0 : width - timeWidth - 1, + Pango.Alignment.RIGHT); - _drawInstruction(width, height, leg, start) { - let legRow = new TransitLegRow.TransitLegRow({ - visible: true, - leg: leg, - start: start, - print: true - }); - - this._renderWidget(legRow, width, height); + this._addSurface(surface, x, y, pageNum); } _drawArrival(width, height) { - let arrivalRow = new TransitArrivalRow.TransitArrivalRow({ - visible: true, - itinerary: this._itinerary, - print: true - }); - - this._renderWidget(arrivalRow, width, height); + let pageNum = this.numPages - 1; + let x = this._cursorX; + let y = this._cursorY; + let surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, width, height); + let cr = new Cairo.Context(surface); + let lastLeg = this._itinerary.legs[this._itinerary.legs.length - 1]; + + this._drawIcon(cr, 'maps-point-end-symbolic', width, height); + // draw the arrival text + this._drawTextVerticallyCentered(cr, Transit.getArrivalLabel(lastLeg), + width - height * 3, + height, this._rtl ? height * 2 : height, + Pango.Alignment.LEFT); + // draw arrival time + this._drawTextVerticallyCentered(cr, lastLeg.prettyPrintArrivalTime(), + height, height, + this._rtl ? 0 : width - height - 1, + Pango.Alignment.RIGHT); + + this._addSurface(surface, x, y, pageNum); } _legHasMiniMap(index) { -- cgit v1.2.1