Skip to content

Commit a1d8558

Browse files
committed
Improved text display and font setting. Menu icons scale with DPI
1 parent 43688ba commit a1d8558

File tree

11 files changed

+190
-138
lines changed

11 files changed

+190
-138
lines changed

.github/workflows/main.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on:
55
pull_request:
66

77
env:
8-
version: 1.1.4
8+
version: 1.1.5
99

1010
jobs:
1111
mingw:

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
TARGET = gw
2-
VERSION = "1.1.4"
2+
VERSION = "1.1.5"
33
.PHONY: default all debug clean
44
default: $(TARGET)
55
all: default

deps/gw.desktop

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[Desktop Entry]
22
Encoding=UTF-8
3-
Version=1.1.4
3+
Version=1.1.5
44
Type=Application
55
Terminal=true
66
Exec=bash -c "/usr/bin/gw"

src/drawing.cpp

+36-57
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ namespace Drawing {
4141
struct TextItemIns{
4242
sk_sp<SkTextBlob> text;
4343
float x, y;
44-
// float box_x, box_y;
4544
float box_y, box_w;
4645
};
4746

@@ -63,6 +62,9 @@ namespace Drawing {
6362
float yOffsetAll = refSpace;
6463

6564
for (auto &cl: collections) {
65+
if (cl.skipDrawingCoverage) {
66+
continue;
67+
}
6668
cl.skipDrawingCoverage = true;
6769

6870
if (cl.bamIdx != last_bamIdx) {
@@ -78,17 +80,11 @@ namespace Drawing {
7880
Segs::findMismatches(opts, cl);
7981
}
8082

81-
// double tot, mean, n;
8283
const std::vector<int> &covArr_r = cl.covArr;
8384
std::vector<float> c;
8485
c.resize(cl.covArr.size());
8586
c[0] = (float) cl.covArr[0];
8687
int cMaxi = (c[0] > 10) ? (int) c[0] : 10;
87-
// tot = (float) c[0];
88-
// n = 0;
89-
// if (tot > 0) {
90-
// n += 1;
91-
// }
9288
float cMax;
9389
bool processThis = draw_mismatch_info && !cl.collection_processed;
9490
for (size_t i = 1; i < c.size(); ++i) { // cum sum
@@ -97,8 +93,6 @@ namespace Drawing {
9793
cMaxi = (int) c[i];
9894
}
9995
if (c[i] > 0) {
100-
// tot += c[i];
101-
// n += 1;
10296
// normalise mismatched bases to nearest whole percentage (avoids extra memory allocation)
10397
if (processThis) { //
10498
if (mmVector[i].A || mmVector[i].T || mmVector[i].C || mmVector[i].G) {
@@ -116,12 +110,6 @@ namespace Drawing {
116110
}
117111
cl.collection_processed = true;
118112
cl.maxCoverage = cMaxi;
119-
// if (n > 0) {
120-
// mean = tot / n;
121-
// mean = ((float) ((int) (mean * 10))) / 10;
122-
// } else {
123-
// mean = 0;
124-
// }
125113

126114
if (opts.log2_cov) {
127115
for (size_t i = 0; i < c.size(); ++i) {
@@ -311,14 +299,6 @@ namespace Drawing {
311299
path.lineTo(xOffset + 6 * monitorScale, covY + yOffsetAll);
312300
canvas->drawPath(path, theme.lcJoins);
313301

314-
// char *ap = indelChars;
315-
// ap += std::sprintf(indelChars, "%s", "avg. ");
316-
// std::sprintf(ap, "%.1f", mean);
317-
318-
// if (covY > fonts.overlayHeight * 3) { // dont overlap text
319-
// blob = SkTextBlob::MakeFromString(indelChars, fonts.overlay);
320-
// canvas->drawTextBlob(blob, xOffset + 8 * monitorScale, covY_f + yOffsetAll + (fonts.overlayHeight * 2), theme.tcDel);
321-
// }
322302
last_bamIdx = cl.bamIdx;
323303

324304
// Draw data labels when alignments are not shown
@@ -795,55 +775,58 @@ namespace Drawing {
795775
}
796776
}
797777

798-
void drawDeletionLine(const Segs::Align &a, SkCanvas *canvas, SkPath &path, const Themes::IniOptions &opts,
799-
const Themes::Fonts &fonts,
800-
int regionBegin, int Y, int regionLen, int starti, int lastEndi,
801-
float regionPixels, float xScaling, float yScaling, float xOffset, float yOffset,
802-
float textDrop, std::vector<TextItem> &text, bool indelTextFits) {
803-
778+
void drawDeletionLine(SkCanvas *canvas, SkPath &path, const Themes::IniOptions &opts,
779+
const Themes::Fonts &fonts,
780+
int regionBegin, int Y, int regionLen, int starti, int lastEndi,
781+
float regionPixels, float xScaling, float yScaling, float xOffset, float yOffset,
782+
std::vector<TextItem> &text, bool indelTextFits) {
804783
int isize = starti - lastEndi;
805784
int lastEnd = lastEndi - regionBegin;
806-
starti -= regionBegin;
807-
808-
int size = starti - lastEnd;
785+
int startRelative = starti - regionBegin;
786+
int size = startRelative - lastEnd;
809787
if (size <= 0) {
810788
return;
811789
}
812-
float delBegin = (float) lastEnd * xScaling;
813-
float delEnd = delBegin + ((float) size * xScaling);
814-
float yh = ((float) Y + (float) polygonHeight * (float) 0.5) * yScaling + yOffset;
790+
float delBegin = lastEnd * xScaling;
791+
float delEnd = delBegin + (size * xScaling);
792+
float yh = (Y + polygonHeight * 0.5) * yScaling + yOffset;
815793

816794
if (isize >= opts.indel_length) {
817-
if (regionLen < 500000 && indelTextFits) { // line and text
795+
if (regionLen < 500000 && indelTextFits) {
818796
std::sprintf(indelChars, "%d", isize);
819-
size_t sl = strlen(indelChars);
820-
float textW = fonts.textWidths[sl - 1];
821-
float textBegin = (((float) lastEnd + (float) size / 2) * xScaling) - (textW / 2);
822-
float textEnd = textBegin + textW;
797+
size_t textLength = strlen(indelChars);
798+
float textWidth = fonts.textWidths[textLength - 1];
799+
float textCenter = ((lastEnd + size / 2.0f) * xScaling);
800+
float textBegin = textCenter - (textWidth / 2.0f);
801+
float textEnd = textBegin + textWidth;
802+
803+
// Adjust if text would be off-screen
823804
if (textBegin < 0) {
824805
textBegin = 0;
825-
textEnd = textW;
806+
textEnd = textWidth;
826807
} else if (textEnd > regionPixels) {
827-
textBegin = regionPixels - textW;
808+
textBegin = regionPixels - textWidth;
828809
textEnd = regionPixels;
829810
}
830-
text.emplace_back() = {SkTextBlob::MakeFromString(indelChars, fonts.overlay),
831-
textBegin + xOffset,
832-
((float) Y + polygonHeight) * yScaling - textDrop + yOffset};
833-
811+
float textYPosition = yh + (fonts.overlayHeight / 2);
812+
text.emplace_back() = {
813+
SkTextBlob::MakeFromString(indelChars, fonts.overlay),
814+
textBegin + xOffset,
815+
textYPosition
816+
};
834817
if (textBegin > delBegin) {
835818
drawHLine(canvas, path, opts.theme.lcJoins, delBegin + xOffset, yh, textBegin + xOffset);
836819
drawHLine(canvas, path, opts.theme.lcJoins, textEnd + xOffset, yh, delEnd + xOffset);
837820
}
838-
} else { // dot only
821+
} else { // Draw dot or line without text
839822
delEnd = std::min(regionPixels, delEnd);
840823
if (delEnd - delBegin < 2) {
841824
canvas->drawPoint(delBegin + xOffset, yh, opts.theme.lcBright);
842825
} else {
843826
drawHLine(canvas, path, opts.theme.lcJoins, delBegin + xOffset, yh, delEnd + xOffset);
844827
}
845828
}
846-
} else if ((float) size / (float) regionLen > 0.0005) { // (regionLen < 50000 || size > 100) { // line only
829+
} else if ((float)size / (float)regionLen > 0.0005) { // Draw small deletions but only if they're visible enough
847830
delEnd = std::min(regionPixels, delEnd);
848831
drawHLine(canvas, path, opts.theme.lcJoins, delBegin + xOffset, yh, delEnd + xOffset);
849832
}
@@ -1059,10 +1042,8 @@ namespace Drawing {
10591042
continue; // insertion
10601043
}
10611044
if (lastEnd <= regionEnd && regionBegin <= starti) {
1062-
drawDeletionLine(a, canvas, path, opts, fonts,
1063-
regionBegin, Y, regionLen, starti, lastEnd,
1064-
regionPixels, xScaling, yScaling, xOffset, yOffset,
1065-
textDrop, text_del, indelTextFits);
1045+
drawDeletionLine(canvas, path, opts, fonts, regionBegin, Y, regionLen, starti, lastEnd,
1046+
regionPixels, xScaling, yScaling, xOffset, yOffset, text_del, indelTextFits);
10661047
}
10671048
}
10681049

@@ -1162,13 +1143,11 @@ namespace Drawing {
11621143
std::sprintf(indelChars, "%d", ins.length);
11631144
size_t sl = strlen(indelChars);
11641145
textW = fonts.textWidths[sl - 1];
1165-
if (ins.length > (uint32_t) opts.indel_length) {
1146+
if (ins.length >= (uint32_t) opts.indel_length) {
11661147
if (regionLen < 500000 && indelTextFits) { // line and text
1167-
// float yScaledOffset = (Y * yScaling) + yOffset;
11681148
text_ins.emplace_back() = {SkTextBlob::MakeFromString(indelChars, fonts.overlay),
11691149
(float)(p - (textW * 0.5) + xOffset - monitorScale),
11701150
yScaledOffset + polygonHeight - textDrop,
1171-
//((Y + polygonHeight) * yScaling) + yOffset - textDrop,
11721151
yScaledOffset,
11731152
std::fmax((float)textW + monitorScale + monitorScale, ins_block_w)};
11741153

@@ -1345,7 +1324,7 @@ namespace Drawing {
13451324
double mmPosOffset = monitorScale; // draw position of boxes
13461325
if (scale_bar) {
13471326
mmPosOffset = gap + h + gap + monitorScale + (gap*0.25);
1348-
yp = gap + h + gap + h + monitorScale;
1327+
yp = gap + h + gap + monitorScale + h + (gap*0.25);
13491328
} else {
13501329
mmPosOffset = monitorScale + monitorScale;
13511330
yp = h + monitorScale + monitorScale;
@@ -2236,7 +2215,7 @@ namespace Drawing {
22362215
canvas->save();
22372216
clip.setXYWH(plot_gap + (regionIdx * colWidth), 1, scaleWidth, fonts.overlayHeight * 2 + plot_gap);
22382217
canvas->clipRect(clip, SkClipOp::kIntersect );
2239-
canvas->drawRect(clip, opts.theme.bgPaint);
2218+
// canvas->drawRect(clip, opts.theme.bgPaint);
22402219

22412220
int position = (region.start / (int)nice_tick) * (int)nice_tick;
22422221
int num_divisions = nice_range / nice_tick;

src/gw_version.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#include "gw_version.h"
2-
const char GW_VERSION[] = "1.1.4";
2+
const char GW_VERSION[] = "1.1.5";

src/main.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
#include <emscripten.h>
3030
#endif
3131

32-
// note to developer - update version in Makefile, workflows/main.yml, and deps/gw.desktop, and installers .md in docs (post release)
32+
// note to developer - update version in gw_version.h, Makefile, workflows/main.yml, and deps/gw.desktop, and installers .md in docs (post release)
3333

3434
// skia context has to be managed from global space
3535
GrDirectContext *sContext = nullptr;

src/menu.cpp

+66-28
Original file line numberDiff line numberDiff line change
@@ -100,18 +100,33 @@ namespace Menu {
100100

101101
void drawMenu(SkCanvas *canvas, Themes::IniOptions &opts, Themes::Fonts &fonts, float monitorScale, float fb_width, float fb_height,
102102
std::string inputText, int charIndex) {
103+
103104
SkRect rect;
104105
SkPath path;
106+
107+
float baseControlBoxSize = 18.0f; // Base control box size
108+
float baseVGap = 3.0f; // Base vertical gap
109+
float baseStrokeWidth = 1.5f; // Base stroke width
110+
float baseIconPadding = 4.0f; // Reduced padding to make icons bigger
111+
float baseMenuWidth = 28.0f; // Base menu width multiplier
112+
105113
float pad = fonts.overlayHeight;
106-
float v_gap = 3 * monitorScale;
107-
float control_box_h = 18 * monitorScale; //35;
114+
float v_gap = baseVGap * monitorScale;
115+
float control_box_h = baseControlBoxSize * monitorScale;
116+
float stroke_width = baseStrokeWidth * monitorScale;
117+
float icon_padding = baseIconPadding * monitorScale;
118+
119+
// Position
108120
float y = v_gap;
109121
float x = v_gap;
110-
float m_width = 28 * fonts.overlayWidth;
111-
auto m_height = (float)(pad * 1.5);
122+
float m_width = baseMenuWidth * fonts.overlayWidth;
123+
auto m_height = pad * 1.5f;
124+
125+
// Set up paints
112126
SkPaint bg;
113127
SkPaint menuBg;
114128
SkPaint tcMenu;
129+
115130
if (opts.theme_str != "igv") {
116131
bg.setARGB(255, 35, 35, 45);
117132
tcMenu.setARGB(255, 255, 255, 255);
@@ -124,59 +139,82 @@ namespace Menu {
124139
tcMenu.setStyle(SkPaint::kStrokeAndFill_Style);
125140
tcMenu.setAntiAlias(true);
126141

142+
// Draw menu background
127143
rect.setXYWH(0, 0, 20000, m_height);
128144
canvas->drawRect(rect, opts.theme.bgPaint);
129145

130146
rect.setXYWH(0, 0, m_width + v_gap, 20000);
131147
canvas->drawRect(rect, bg);
148+
132149
std::vector<std::string> btns = availableButtonsStr(opts.menu_table);
133150
float x2 = x;
151+
152+
// Calculate rounded corner radius based on scale
153+
float cornerRadius = 2.5f * monitorScale;
134154
for (auto& b : btns) {
135155
rect.setXYWH(x2, y, control_box_h, control_box_h);
136156
if (b == opts.control_level) {
137-
canvas->drawRoundRect(rect, 5, 5, menuBg);
157+
canvas->drawRoundRect(rect, cornerRadius, cornerRadius, menuBg);
138158
} else {
139-
canvas->drawRoundRect(rect, 5, 5, bg);
159+
canvas->drawRoundRect(rect, cornerRadius, cornerRadius, bg);
140160
}
161+
162+
float iconSize = control_box_h - (2 * icon_padding);
163+
float iconLeft = x2 + icon_padding;
164+
float iconRight = x2 + control_box_h - icon_padding;
165+
float iconTop = y + icon_padding;
166+
float iconBottom = y + control_box_h - icon_padding;
167+
float iconMiddleX = x2 + (control_box_h / 2);
168+
float iconMiddleY = y + (control_box_h / 2);
169+
141170
if (b == "close") {
142-
tcMenu.setStrokeWidth(3);
171+
tcMenu.setStrokeWidth(stroke_width);
143172
path.reset();
144-
path.moveTo(x2 + 10, y + 10);
145-
path.lineTo(x2 + control_box_h - 10, y + control_box_h - 10);
146-
path.moveTo(x2 + 10, y + control_box_h - 10);
147-
path.lineTo(x2 + control_box_h - 10, y + 10);
173+
path.moveTo(iconLeft, iconTop);
174+
path.lineTo(iconRight, iconBottom);
175+
path.moveTo(iconLeft, iconBottom);
176+
path.lineTo(iconRight, iconTop);
148177
canvas->drawPath(path, tcMenu);
149178
tcMenu.setStrokeWidth(0);
150179
} else if (b == "back") {
151180
path.reset();
152-
path.moveTo(x2 + control_box_h - 10, y + 10);
153-
path.lineTo(x2 + 10, y + (control_box_h/2));
154-
path.lineTo(x2 + control_box_h - 10, y + control_box_h - 10);
181+
path.moveTo(iconRight, iconTop);
182+
path.lineTo(iconLeft, iconMiddleY);
183+
path.lineTo(iconRight, iconBottom);
155184
canvas->drawPath(path, tcMenu);
156185
} else if (b == "save") {
186+
float cornerCut = 4.0f * monitorScale; // Size of corner cutout
157187
path.reset();
158-
path.moveTo(x2 + 8, y + 8);
159-
path.lineTo(x2 + 8, y + control_box_h - 8);
160-
path.lineTo(x2 + control_box_h - 8, y + control_box_h - 8);
161-
path.lineTo(x2 + control_box_h - 8, y + 12);
162-
path.lineTo(x2 + control_box_h - 12, y + 8);
188+
path.moveTo(iconLeft, iconTop);
189+
path.lineTo(iconLeft, iconBottom);
190+
path.lineTo(iconRight, iconBottom);
191+
path.lineTo(iconRight, iconTop + cornerCut);
192+
path.lineTo(iconRight - cornerCut, iconTop);
193+
path.close();
163194
canvas->drawPath(path, tcMenu);
164-
rect.setXYWH(x2 + 12, y + 12, control_box_h - 26, 6);
195+
float lineHeight = stroke_width * 1.2f;
196+
float lineGap = (iconBottom - iconTop - (3 * lineHeight)) / 3;
197+
rect.setXYWH(
198+
iconLeft + (icon_padding * 0.6f),
199+
iconTop + lineGap,// * 2 + lineHeight,
200+
iconSize - (icon_padding * 1.8f),
201+
lineHeight * 1.4f
202+
);
165203
canvas->drawRect(rect, ((b == opts.control_level) ? menuBg : bg));
166204
} else if (b == "add") {
167-
tcMenu.setStrokeWidth(3);
205+
tcMenu.setStrokeWidth(stroke_width);
168206
path.reset();
169-
path.moveTo(x2 + (control_box_h / 2), y + 10);
170-
path.lineTo(x2 + (control_box_h / 2), y + control_box_h - 10);
171-
path.moveTo(x2 + 10, y + (control_box_h / 2));
172-
path.lineTo(x2 + control_box_h - 10, y + (control_box_h / 2));
207+
path.moveTo(iconMiddleX, iconTop);
208+
path.lineTo(iconMiddleX, iconBottom);
209+
path.moveTo(iconLeft, iconMiddleY);
210+
path.lineTo(iconRight, iconMiddleY);
173211
canvas->drawPath(path, tcMenu);
174212
tcMenu.setStrokeWidth(0);
175213
} else if (b == "delete") {
176-
tcMenu.setStrokeWidth(3);
214+
tcMenu.setStrokeWidth(stroke_width);
177215
path.reset();
178-
path.moveTo(x2 + 10, y + (control_box_h / 2));
179-
path.lineTo(x2 + control_box_h - 10, y + (control_box_h / 2));
216+
path.moveTo(iconLeft, iconMiddleY);
217+
path.lineTo(iconRight, iconMiddleY);
180218
canvas->drawPath(path, tcMenu);
181219
tcMenu.setStrokeWidth(0);
182220
}

0 commit comments

Comments
 (0)