more hacky bugfixes, no actual fundamental flaw fixes :(

This commit is contained in:
Adam D. Ruppe 2018-11-25 18:15:12 -05:00
parent d3c7f3fddc
commit 1cfacea360
2 changed files with 72 additions and 228 deletions

View File

@ -1835,6 +1835,17 @@ class ScrollableWidget : Widget {
horizontalScrollBar = new HorizontalScrollbar(horizontalScrollbarHolder);
verticalScrollBar = new VerticalScrollbar(verticalScrollbarHolder);
// TOTAL HACKS
horizontalScrollBar.addEventListener("mousedown", (Event event) { event.preventDefault(); });
verticalScrollBar.addEventListener("mousedown", (Event event) { event.preventDefault(); });
horizontalScrollBar.addEventListener("mousemove", (Event event) { event.preventDefault(); });
verticalScrollBar.addEventListener("mousemove", (Event event) { event.preventDefault(); });
/*
clientAreaHolder = new FixedPosition(this);
clientArea = new ScrollableClientWidget(clientAreaHolder);
*/
horizontalScrollbarHolder.showing_ = false;
verticalScrollbarHolder.showing_ = false;
@ -1894,6 +1905,11 @@ class ScrollableWidget : Widget {
VerticalScrollbar verticalScrollBar;
HorizontalScrollbar horizontalScrollBar;
/*
FixedPosition clientAreaHolder;
Widget clientArea;
*/
}
version(custom_widgets)
@ -1910,6 +1926,13 @@ class ScrollableWidget : Widget {
verticalScrollbarHolder.x = this.width - verticalScrollBar.minWidth();
verticalScrollbarHolder.y = 0 + 2;
/*
clientAreaHolder.x = 0;
clientAreaHolder.y = 0;
clientAreaHolder.width = this.width - verticalScrollBar.width;
clientAreaHolder.height = this.height - horizontalScrollBar.height;
*/
if(contentWidth_ <= this.width)
scrollOrigin_.x = 0;
if(contentHeight_ <= this.height)
@ -2182,7 +2205,7 @@ class ScrollableWidget : Widget {
painter.originX = painter.originX - scrollOrigin.x;
painter.originY = painter.originY - scrollOrigin.y;
if(force || redrawRequested) {
painter.setClipRectangle(scrollOrigin, viewportWidth(), viewportHeight());
painter.setClipRectangle(scrollOrigin + Point(2, 2) /* border */, viewportWidth() - 4 /* border */, viewportHeight() - 4 /* border */);
//erase(painter); // we paintFrameAndBackground above so no need
paint(painter);
@ -2199,6 +2222,17 @@ class ScrollableWidget : Widget {
}
}
/*
class ScrollableClientWidget : Widget {
this(Widget parent) {
super(parent);
}
override void paint(ScreenPainter p) {
parent.paint(p);
}
}
*/
///
abstract class ScrollbarBase : Widget {
///
@ -5434,6 +5468,12 @@ abstract class EditableTextWidget : EditableTextWidgetParent {
version(custom_widgets)
override void paintFrameAndBackground(ScreenPainter painter) {
this.draw3dFrame(painter, FrameStyle.sunk, Color.white);
if(horizontalScrollbarHolder.showing && verticalScrollbarHolder.showing) {
// just paint over the lower-right corner
painter.outlineColor = windowBackgroundColor;
painter.fillColor = windowBackgroundColor;
painter.drawRectangle(Point(width - 16, height - 16), Size(16, 16));
}
}
version(win32_widgets) { /* will do it with Windows calls in the classes */ }
@ -5480,9 +5520,11 @@ abstract class EditableTextWidget : EditableTextWidgetParent {
super.defaultEventHandler_mousedown(ev);
if(parentWindow.win.closed) return;
if(ev.button == MouseButton.left) {
if(textLayout.selectNone())
redraw();
textLayout.moveCaretToPixelCoordinates(ev.clientX, ev.clientY);
this.focus();
this.parentWindow.win.grabInput();
//this.parentWindow.win.grabInput();
} else if(ev.button == MouseButton.middle) {
static if(UsingSimpledisplayX11) {
getPrimarySelection(parentWindow.win, (txt) {
@ -5498,7 +5540,7 @@ abstract class EditableTextWidget : EditableTextWidgetParent {
version(custom_widgets)
override void defaultEventHandler_mouseup(Event ev) {
this.parentWindow.win.releaseInputGrab();
//this.parentWindow.win.releaseInputGrab();
super.defaultEventHandler_mouseup(ev);
}

View File

@ -6343,6 +6343,15 @@ struct ScreenPainter {
impl.drawRectangle(upperLeft.x, upperLeft.y, width, height);
}
/// ditto
void drawRectangle(Point upperLeft, Size size) {
if(impl is null) return;
if(isClipped(upperLeft, size.width, size.height)) return;
transform(upperLeft);
impl.drawRectangle(upperLeft.x, upperLeft.y, size.width, size.height);
}
/// ditto
void drawRectangle(Point upperLeft, Point lowerRightInclusive) {
if(impl is null) return;
if(isClipped(upperLeft, lowerRightInclusive + Point(1, 1))) return;
@ -8455,6 +8464,7 @@ version(X11) {
/// for cross-platform compatibility.
//__gshared string xfontstr = "-*-dejavu sans-medium-r-*-*-12-*-*-*-*-*-*-*";
__gshared string xfontstr = "-*-lucida-medium-r-normal-sans-12-*-*-*-*-*-*-*";
//__gshared string xfontstr = "-*-fixed-medium-r-*-*-14-*-*-*-*-*-*-*";
alias int delegate(XEvent) NativeEventHandler;
alias Window NativeWindowHandle;
@ -13014,229 +13024,17 @@ version(X11) {
}
mixin template ExperimentalTextComponent2() {
enum TextFormat : ushort {
// decorations
underline = 1,
strikethrough = 2,
// font selectors
bold = 0x4000 | 1, // weight 700
light = 0x4000 | 2, // weight 300
veryBoldOrLight = 0x4000 | 4, // weight 100 with light, weight 900 with bold
// bold | light is really invalid but should give weight 500
// veryBoldOrLight without one of the others should just give the default for the font; it should be ignored.
italic = 0x4000 | 8,
smallcaps = 0x4000 | 16,
}
struct Decoration {
ushort id;
Color foreground;
Color background;
ushort textFormat;
void* font;
}
Decoration[] decorations;
struct TextState {
char[] text;
int[] x;
int[] y;
ushort[] decorationId;
int length;
int caret;
void makeGap(int where, int minLength) {
int gapSize = 0;
int at = where;
while(at < text.length && text[at] == 0xff) {
at++;
gapSize++;
}
if(gapSize >= minLength)
return;
// try to gather gap from behind us, if any
/*
at = where - 32;
if(at < 0)
at = 0;
while(at < where - 1) {
if(text[at] == 0xff) {
text[at] = text[at + 1];
x[at] = x[at + 1];
y[at] = y[at + 1];
decorationId[at] = decorationId[at + 1];
text[at + 1] = 0xff;
gapSize++;
}
at++;
}
if(gapSize >= minLength)
return;
*/
keep_trying:
at = where;
while(at + 1 < text.length) {
// FIXME it needs to work on a whole block, not just one char
if(text[at + 1] == 0xff) {
text[at + 1] = text[at];
x[at + 1] = x[at];
y[at + 1] = y[at];
decorationId[at + 1] = decorationId[at];
text[at] = 0xff;
gapSize++;
if(gapSize >= minLength)
return;
}
at++;
}
if(gapSize < minLength) {
auto increase = 16;
if(minLength - gapSize > 16)
increase = minLength - gapSize;
text.length += increase;
x.length += increase;
y.length += increase;
decorationId.length += increase;
text[$ - increase .. $] = 0xff;
goto keep_trying;
}
}
void insert(dchar c) {
makeGap(caret, 1);
text[caret] = cast(char) c;
caret++;
length++;
layout(caret - 1, cast(int) text.length, false);
}
string toPlainText() {
string s;
s.reserve(length);
foreach(char ch; text)
if(ch != 0xff)
s ~= ch;
return s;
}
void resetContents(in char[] to) {
if(text.length < to.length * 2) {
text.length = to.length * 2;
x.length = text.length;
y.length = text.length;
decorationId.length = text.length;
}
int textPos = 0;
int skipped = 0;
foreach(ch; to) {
if(ch == 13) {
++skipped;
continue;
}
text[textPos++] = ch;
text[textPos++] = 0xff;
}
text[textPos .. $] = 0xff;
length = cast(int) to.length - skipped;
decorationId[0 .. length] = 0;
layout(0, text.length, true);
}
int lineHeight = 14;
int letterWidth = 7;
int tabStop = 4;
void layout(int start, int end, bool forceAll) {
int x = 0, y = 0;
foreach(idx, char ch; text[start .. end]) {
if(ch == 0xff)
continue;
if(!forceAll && this.x[start + idx] == x && this.y[start + idx] == y)
break; // seems to already be done!
this.x[start + idx] = x;
this.y[start + idx] = y;
// FIXME unicode
if(ch == '\n') {
x = 0;
y += lineHeight;
} else if(ch == '\t') {
x += x % (letterWidth * tabStop);
} else {
x += letterWidth;
}
}
}
void drawInto(ScreenPainter painter, int dx, int dy, int sx, int sy, int width, int height) {
//char[6] buffer;
// FIXME unicode
painter.outlineColor = Color.white;
painter.fillColor = Color.white;
painter.drawRectangle(Point(dx, dy), width, height);
painter.outlineColor = Color.black;
if(length == 0)
return;
int startingIdx = 0;
if(sx > 0 || sy > 0) {
int lastSearched = text.length;
// binary search till we get the first visible item
startingIdx = text.length / 2;
keep_searching:
while(startingIdx >= 0 && text[startingIdx] == 0xff)
--startingIdx;
while(text[startingIdx] == 0xff && startingIdx < text.length)
++startingIdx;
if(startingIdx == text.length)
assert(0); // we're apparently empty! why didn't length == 0?
if(this.x[startingIdx] > sx || this.y[startingIdx] > sy) {
// FIXME
// too far ahead, search backward
lastSearched = startingIdx;
startingIdx = startingIdx / 2;
goto keep_searching;
} else {
// this is probably good enough but let's try to be more precise
//startingIdx = (lastSearched - startingIdx) / 2;
//goto keep_searching;
}
}
foreach(idx, char ch; text[startingIdx .. $]) {
if(ch == 0xff)
continue;
int drawX = dx + this.x[startingIdx + idx] - sx;
int drawY = dy + this.y[startingIdx + idx] - sy;
if(drawX - dx > width)
continue;
if(drawY - dy > height)
break;
painter.drawText(Point(drawX, drawY), "" ~ ch);
}
}
}
/+
Stage 1: get it working monospace
Stage 2: use proportional font
Stage 3: allow changes in inline style
Stage 4: allow new fonts and sizes in the middle
Stage 5: optimize gap buffer
Stage 6: optimize layout
Stage 7: word wrap
Stage 8: justification
Stage 9: editing, selection, etc.
+/
}
@ -14097,8 +13895,12 @@ mixin template ExperimentalTextComponent() {
moveDocumentStart(selectionStart);
moveDocumentEnd(selectionEnd);
}
void selectNone() {
selectionStart = selectionEnd = Caret.init;
bool selectNone() {
if(selectionStart != selectionEnd) {
selectionStart = selectionEnd = Caret.init;
return true;
}
return false;
}
/// Rich text editing api. These allow you to manipulate the meta data of the current element and add new elements.