From 5816418007b75c3c95f47536ed4d39bb3eb262b5 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 2 Feb 2016 13:47:49 +1100 Subject: [PATCH] devel --- core-doc.c | 8 ++ doc-text.c | 4 + edlib.c | 3 +- lib-messageline.c | 2 +- mode-emacs.c | 5 +- python/display-pygtk.py | 64 +++++++++++- python/render-present.py | 221 +++++++++++++++++++++++++++++++++------ render-lines.c | 59 ++++++++++- 8 files changed, 327 insertions(+), 39 deletions(-) diff --git a/core-doc.c b/core-doc.c index 5b046176..f6ffff08 100644 --- a/core-doc.c +++ b/core-doc.c @@ -411,6 +411,14 @@ DEF_CMD(doc_handle) pane_add_notify(ci->focus, dd->doc->home, "Notify:Replace"); return 1; } + if (strcmp(ci->key, "Request:Notify:Recentre") == 0) { + pane_add_notify(ci->focus, dd->doc->home, "Notify:Recentre"); + return 1; + } + if (strcmp(ci->key, "doc:Recentre") == 0) { + pane_notify(dd->doc->home, "Notify:Recentre", ci->mark, NULL); + return 1; + } if (strcmp(ci->key, "Clone") == 0) { struct pane *p = doc_attach(ci->focus, dd->doc); diff --git a/doc-text.c b/doc-text.c index ae0acf15..f4bf75c1 100644 --- a/doc-text.c +++ b/doc-text.c @@ -578,6 +578,10 @@ static int text_update_following_after_change(struct text *t, struct doc_ref *po *pos = *epos; return 1; } + /* HACK? */ + if (text_ref_same(t, pos, epos)) + /* KEep going*/ + return 1; /* This is beyond the change point and no deletion or split * happened here, so all done. */ diff --git a/edlib.c b/edlib.c index f1d9664a..f513a865 100644 --- a/edlib.c +++ b/edlib.c @@ -129,9 +129,8 @@ int main(int argc, char *argv[]) global = pane_attach(global, "global-keymap", NULL, NULL); call5("global-set-keymap", global, 0, NULL, "mode-emacs", 0); b = pane_attach(global, "tile", NULL, NULL); - p = doc_from_text(b, "*Welcome*", WelcomeText); + p = doc_attach_view(b, pane2ed(b)->docs->home, NULL); } - pane_refresh(&ed->root); while (call3("event:run", vroot, 0, NULL) == 1) ; diff --git a/lib-messageline.c b/lib-messageline.c index 7722aad5..0b407119 100644 --- a/lib-messageline.c +++ b/lib-messageline.c @@ -79,7 +79,7 @@ DEF_CMD(messageline_handle) else pane_resize(ci->home, 0, ci->home->parent->h - mli->height, ci->home->parent->w, mli->height); - pane_clear(mli->line, "bg:cyan"); + pane_clear(mli->line, "bg:white"); if (mli->message) pane_str(mli->line, mli->message, "bold,fg:red,bg:cyan", 0, 0 + mli->ascent); diff --git a/mode-emacs.c b/mode-emacs.c index cf8d1ca0..16dc71f9 100644 --- a/mode-emacs.c +++ b/mode-emacs.c @@ -82,7 +82,7 @@ REDEF_CMD(emacs_move) if (!ret) return 0; - if (strcmp(mv->type, "Move-View-Large") == 0 && old_x >= 0) { + if (strcmp(mv->type, "Move-View-Large") == 0 && old_x >= 0 && ret != 10) { /* Might have lost the cursor - place it at top or * bottom of view, but make sure it moves only in the * right direction. @@ -167,6 +167,7 @@ static struct str_command { {CMD(emacs_str), "WindowOP", "close-others", "emCX-Chr-1"}, {CMD(emacs_str), "WindowOP", "split-y", "emCX-Chr-2"}, {CMD(emacs_str), "WindowOP", "split-x", "emCX-Chr-3"}, + {CMD(emacs_str), "DisplayOP", "new", "emCX5-Chr-2"}, {CMD(emacs_str), "WindowOP", "close", "emCX-Chr-0"}, {CMD(emacs_str), "Display", "refresh", "C-Chr-L"}, {CMD(emacs_str), "Abort", NULL, "C-Chr-G"}, @@ -597,10 +598,12 @@ static void emacs_init(void) unsigned i; struct command *cx_cmd = key_register_prefix("emCX-"); struct command *cx4_cmd = key_register_prefix("emCX4-"); + struct command *cx5_cmd = key_register_prefix("emCX5-"); struct map *m = key_alloc(); key_add(m, "C-Chr-X", cx_cmd); key_add(m, "emCX-Chr-4", cx4_cmd); + key_add(m, "emCX-Chr-5", cx5_cmd); key_add(m, "ESC", &emacs_meta); for (i = 0; i < ARRAY_SIZE(move_commands); i++) { diff --git a/python/display-pygtk.py b/python/display-pygtk.py index 6ec87639..3847a750 100644 --- a/python/display-pygtk.py +++ b/python/display-pygtk.py @@ -15,6 +15,18 @@ import thread import gobject import glib +def take(name, place, args, default=None): + if name in args: + place.append(args[name]) + else: + place.append(default) + return 1 + +def attach(p, mode): + pl=[] + p.call("attach-%s"%mode, lambda key,**a:take('focus', pl, a)) + return pl[0] + class EdDisplay(gtk.Window): def __init__(self, home): gtk.Window.__init__(self) @@ -30,6 +42,26 @@ class EdDisplay(gtk.Window): def handle(self, key, **a): + if key == "M-Chr--" or key == "M-Chr-_": + self.pane['scale'] = "%d"%(int(self.pane['scale']) * 100/105) + return 1 + if key == "M-Chr-=" or key == "M-Chr-+": + self.pane['scale'] = "%d"%(int(self.pane['scale']) * 105/100) + return 1 + + if key == "DisplayOP" and a['str'] == "new": + pl=[] + disp = a['home'] + while disp.parent: + disp = disp.parent + disp = EdDisplay(disp) + p = attach(disp.pane, "input"); + p = attach(p, "messageline"); + p = attach(p, "global-keymap") + p.call("global-set-keymap", "mode-emacs"); + p = attach(p, "tile") + return 1 + if key == "Window:fullscreen": if a['numeric'] > 0: self.fullscreen() @@ -44,7 +76,6 @@ class EdDisplay(gtk.Window): if key == "pane-clear": f = a["focus"] if "str2" in a: - print "CLEAR", a['str2'] fg, bg = self.get_colours(a["str2"]) else: fg, bg = self.get_colours("bg:white") @@ -117,7 +148,7 @@ class EdDisplay(gtk.Window): if f.parent.focus != f: extra = False f = f.parent - print x,cx,y,cy,cw,ch,extra,a['numeric'],len(a['str']) + #print x,cx,y,cy,cw,ch,extra,a['numeric'],len(a['str']) if extra: pm.draw_rectangle(self.gc, True, x+cx, y-ascent+cy, cw, ch); @@ -164,6 +195,28 @@ class EdDisplay(gtk.Window): pm.draw_pixbuf(self.gc, scale, 0, 0, x, y) return True + if key == "image-stretch-display": + # 'str' is a file name of an image + # xy is location for top/left + # numeric/extra are max width/height + # I should use a pane-per-image but I'm in a rush + fl = a['str'] + f = a['focus'] + w = a['numeric'] + h = a['extra'] + if h == 0: + h = w + (x,y) = a['xy'] + try: + pb = gtk.gdk.pixbuf_new_from_file(fl) + except: + pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, w, h) + pb.fill(0xff000000) + scale = pb.scale_simple(w, h, gtk.gdk.INTERP_HYPER) + pm = self.get_pixmap(f) + pm.draw_pixbuf(self.gc, scale, 0, 0, x, y) + return True + if key == "Notify:Close": f = a["focus"] if f and f in self.panes: @@ -359,12 +412,17 @@ class EdDisplay(gtk.Window): t = self.text if not self.bg: self.bg = t.window.new_gc() - self.bg.set_foreground(colour) + try: + self.bg.set_foreground(colour) + except: + print 'error colour is', colour, type(colour) + pass (w,h) = pm.get_size() pm.draw_rectangle(self.bg, True, 0, 0, w, h) def new_display(key, home, comm2, **a): disp = EdDisplay(home) + disp.pane['scale'] = "1000" comm2('callback', disp.pane) return 1 diff --git a/python/render-present.py b/python/render-present.py index a6e69d81..bd25ee87 100644 --- a/python/render-present.py +++ b/python/render-present.py @@ -143,7 +143,7 @@ class PresenterPane(edlib.Pane): if globals is not None: self.globals = globals if 'background' in globals: - self['background'] = globals['background'] + self['background'] = 'call:Present-BG:'+globals['background'] if 'scale' in globals: self['scale'] = globals['scale'] self.call("render-lines:redraw") @@ -256,7 +256,7 @@ class PresenterPane(edlib.Pane): pm = None continue - # pm is the start of this page, just need to check next + # pm is the start of a page, just need to check next is vald if pm['next-valid'] != 'yes': next = self.find_page(pm) if not next: @@ -270,6 +270,7 @@ class PresenterPane(edlib.Pane): n.to_mark(next) next.unlink() pm['next-valid'] = 'yes' + pm = None else: if self.marks_same(next, pm.next()): pm['next-valid'] = 'yes' @@ -331,6 +332,7 @@ class PresenterPane(edlib.Pane): la=[] self.call("doc:vmark-get", self.attrview, 2, lambda key,**a: take('mark2', la, a)) line = la[0] + line.to_mark(page) while not next or (line < next and not self.marks_same(line, next)): # There is a line there that we care about - unless EOF @@ -341,32 +343,103 @@ class PresenterPane(edlib.Pane): self.annotate(this, l) line.unlink() - def get_local_attr(self, m, attr): + def line_reval(self, l, page): + while l.prev() is not None and l.prev()['type'] == 'unknown': + l2 = l.prev() + l.unlink() + l = l2 + + if l is None: + la=[] + self.call("doc:vmark-get", self.attrview, 2, + lambda key,**a: take('mark2', la, a)) + l = la[0] + l.to_mark(page) + # l is a good starting point. parse until l.next or page.next + end = l.next() + if end is None: + end = page.next() + while not end or (l < end and not self.marks_same(l, end)): + # There is a line there that we care about - unless EOF + this = l.dup() + txt = self.get_line_at(l) + if not txt: + break + self.annotate(this, txt) + l.unlink() + + def get_local_attr(self, m, attr, page): t = 'attr:' + attr l = self.prev_line(m) while l: if l['type'] == 'unknown': - # Ouch - need to re-evaluate. Just assume still at start-of-line - self.annotate(l, self.print_line_at(l)) - pass + self.line_reval(l, page) + l = self.prev_line(m) + continue + if l['type'] == t: return l['value'] l = l.prev() return None - para_ptn = ['# ', '## ', '> ', '- ', ' ', '!', None, ''] - para_type = ['H1', 'H2', 'I', 'L1', 'C', 'IM', 'BL', 'P'] + paras = { + '# ' : 'H1', + '## ': 'H2', + '>' : 'I', + '- ' : 'L1', + '!' : 'IM', + '' : 'P', + None : 'BL', + ' - ': 'L2', + ' ': {'L2':'L2c', 'L2c':'L2c', 'L1':'L1c', 'L1c': 'L1c', None: 'C'}, + ' ' : {'L2':'L1c', 'L2c':'L1c', 'L1':'L1c', 'L1c': 'L1c', None: 'C'}, + ' ' : {'L2':'L1c', 'L2c':'L1c', 'L1':'L1c', 'L1c': 'L1c', None: 'P'}, + } defaults = { - 'H1': 'center,large,family:serif', - 'H2': 'right:20,fg:red,bold', - 'I': 'left:5,family:Mufferaw', + 'H1': 'center,30,family:serif', + 'H2': 'center,20,fg:red,bold', + 'I': 'left:50,family:Mufferaw', 'C': 'family:mono', - 'L1': 'fg:blue,left:40,family:sans', + 'L1': 'left:20,family:sans,bullet:#,tab:20', + 'L1c': 'left:20,family:sans,tab:20', + 'L2': 'left:40,family:sans,bullet:#,tab:20', + 'L2c': 'left:40,family:sans,tab:20', 'P': 'left:30,family:sans,space-below:20', 'BL': '3', + 'bullet': 'fg:red', + 'bold': 'bold', + 'italic':'italic' } + def get_attr(self, here, mode, page): + v = self.get_local_attr(here, mode, page) + if not v and mode in self.globals: + v = self.globals[mode] + if not v and mode in self.defaults: + v = self.defaults[mode] + if not v: + v = "" + return v + def handle(self, key, **a): + if key == "Present-BG": + cmds = a['str'].split(',') + f = a['focus'] + for c in cmds: + if c[:6] == 'color:': + f.call('pane-clear', c[6:]) + if c[:14] == "image-stretch:": + f.call('image-stretch-display', self.w, self.h, c[14:], (0,0)) + if c[:6] == "image:": + f.call('image-display', self.w, self.h, c[6:], (0,0)) + if c[:8] == "overlay:": + f.call('image-display', self.w/6, self.h*3/4, c[8:], (self.w*5/6, self.h/4)) + if c == "page-local": + page = self.find_pages(a['mark']) + cm = self.get_local_attr(a['mark'], "background", page) + if cm: + cmds.extend(cm.split(',')) + return 1 if key == "render-line-prev": # Go to start of page here = a['mark'] @@ -417,30 +490,62 @@ class PresenterPane(edlib.Pane): cb("callback", self) else: mode = 'P' - for n in range(len(self.para_ptn)): - prefix = self.para_ptn[n] - if prefix == None and line == "": - mode = self.para_type[n] + prefix = None + for pf in self.paras: + if pf == None and line == "": + mode = self.paras[pf] break - if prefix is not None and prefix == line[0:len(prefix)]: - mode = self.para_type[n] - line = line[len(prefix):] - break - v = self.get_local_attr(here, mode) - if not v and mode in self.globals: - v = self.globals[mode] - if not v and mode in self.defaults: - v = self.defaults[mode] - if not v: - v = "" + if (pf and (prefix is None or len(pf) > len(prefix)) and + pf == line[0:len(pf)]): + mode = self.paras[pf] + prefix = pf + + if prefix: + line = line[len(prefix):] + if type(mode) == dict: + # look up type of previous line. + pmode = None + if here.prev() is not None: + pmode = here.prev()['mode'] + if pmode in mode: + mode = mode[pmode] + else: + mode = mode[None] + here['mode'] = mode + v = self.get_attr(here, mode, page) if mode == 'IM': - cb("callback", self, "") + width=200; height=100 + if len(line) > 1 and line[0].isdigit(): + try: + c = line.index(':') + width = int(line[:c]) + except: + c = -1 + + line = line[c+1:] + try: + c = line.index(':') + height = int(line[:c]) + except: + c = -1 + line = line[c+1:] + + cb("callback", self, ""%(width,height)) return 1 line = re.sub("\*([A-Za-z0-9][^*<]*)\*", "\\1", line) - line = re.sub("`([A-Za-z0-9][^*<]*)`", "\\1", line) - line = "<"+v+">"+ line + "" + line = re.sub("`([/A-Za-z0-9][^*<]*)`", "\\1", line) + b = re.match(".*,bullet:([^:,]*)", v) + if b: + vb = self.get_attr(here, 'bullet', page) + if vb: + bl = "<%s>%s" % (vb, b.group(1)) + else: + bl = b.group(1) + line = bl +"<"+v+">"+ line + "" + else: + line = "<"+v+">"+ line + "" line += '\n' if end and (here > end or self.marks_same(here,end)): line += '\f' @@ -478,6 +583,10 @@ class PresenterPane(edlib.Pane): l['type'] = 'unknown' return 1 + if key == "Notify:Recentre": + self.call("Move-View-Pos", a['mark']) + return 1 + if key == "Close": # destroy all marks self.release() @@ -528,10 +637,62 @@ def present_attach(key, focus, comm2, **a): p = PresenterPane(focus) p['render-wrap'] = 'no' p['background'] = 'color:yellow' + p['hide-cursor'] = 'yes' p.call("Request:Notify:Replace") + p.call("Request:Notify:Recentre") p = p.render_attach("lines") comm2('callback', p) return 1 +def get_line_at(focus, m): + # call render-line at m + line = [] + focus.call("render-line", m, -1, lambda key, **a: take('str', line, a, '')) + return line[0] +def present_page(key, focus, mark, **a): + # Assumming 'mark' is either start-of-file (if 'sof') or the start of + # a page, find the start of the next page. Return an untyped mark + # or None if there is no next page. + # A page starts with some ":attr:" lines and then a "# " line. + # If not 'sof' we first need to skip over the start of 'this' page. + if a['numeric'] <= 0: + return 0 + skipping = True + start = mark + m = start.dup(1) + maybe = None + + while True: + if not maybe and not skipping: + maybe = m.dup() + l = get_line_at(focus, m) + if not l: + # End of document + if maybe: + maybe.unlink() + m.unlink() + return 1 + if l[0] == ':': + # attribute - doesn't advance possible start + pass + elif l[0:2] == "# ": + # level-1 heading. This is it if not skipping + if skipping: + skipping = False + else: + m.unlink() + mark.to_mark(maybe) + maybe.unlink() + focus.call("doc:Recentre", mark) + return 1 + else: + # not part of start-of-page + skipping = False + if maybe: + maybe.unlink() + maybe = None + + editor.call("global-set-command", pane, "render-present-attach", present_attach) +editor.call("global-set-command", pane, "Presenter-page", present_page) diff --git a/render-lines.c b/render-lines.c index 918a19d6..28a892fd 100644 --- a/render-lines.c +++ b/render-lines.c @@ -222,6 +222,9 @@ static void update_line_height(struct pane *p, int *h, int *a, int *w, int *cent if ((c=strstr(buf_final(&attr), ",space-below:")) != NULL) { below = atoi(c+13) * scale/1000; } + if ((c=strstr(buf_final(&attr), ",tab:")) != NULL) { + *w = atoi(c+5) * scale / 1000; + } attr_found = 1; update_line_height_attr(p, h, a, w, buf_final(&attr), "", scale); } else { @@ -310,6 +313,7 @@ static void render_line(struct pane *p, char *line, int *yp, int dodraw, int sca int ret = 0; int twidth = 0; int center = 0; + int margin; /* Temporary hack (I hope) */ if (strncmp(line, "w - x - twidth + center; + margin = x; rl->line_height = line_height; buf_init(&attr); buf_append(&attr, ' '); attr.len = 0; @@ -449,10 +454,17 @@ static void render_line(struct pane *p, char *line, int *yp, int dodraw, int sca line += 1; if (a[0] != '/') { + int ln = attr.len; + char *tb; buf_concat_len(&attr, a, line-a); /* mark location with ",," */ attr.b[attr.len-1] = ','; buf_append(&attr, ','); + tb = strstr(buf_final(&attr)+ln, + "tab:"); + if (tb) { + x = margin + atoi(tb+4) * scale / 1000; + } } else { /* strip back to ",," */ if (attr.len > 0) @@ -673,8 +685,12 @@ static int get_scale(struct pane *p) if (!sc) return 1000; - if (sscanf(sc, "x:%d,y:%d", &x, &y) != 2) + if (sscanf(sc, "x:%d,y:%d", &x, &y) != 2) { + scale = atoi(sc); + if (scale > 3) + return scale; return 1000; + } /* 'scale' is pixels per point times 1000. * ":scale:x" is points across pane, so scale = p->w/x*1000 @@ -837,18 +853,37 @@ static void render(struct mark *pm, struct pane *p) char *hdr; char *bg; int scale = get_scale(p); + int hide_cursor = 0; hdr = pane_attr_get(p, "heading"); if (hdr && !*hdr) hdr = NULL; + bg = pane_attr_get(p, "hide-cursor"); + if (bg && strcmp(bg, "yes") == 0) + hide_cursor = 1; restart: + y = 0; bg = pane_attr_get(p, "background"); if (bg && strncmp(bg, "color:", 6) == 0) { char *a; asprintf(&a, "bg:%s", bg+6); pane_clear(p, a); free(a); + } else if (bg && strncmp(bg, "image:", 6) == 0) { + pane_clear(p, "bg:black"); + call_xy7("image-display", p, p->w, p->h, bg+6, NULL, 0, 0, NULL, NULL); + } else if (bg && strncmp(bg, "image-stretch:", 14) == 0) { + pane_clear(p, "bg:black"); + call_xy7("image-stretch-display", p, p->w, p->h, bg+14, NULL, 0, 0, NULL, NULL); + } else if (bg && strncmp(bg, "call:", 5) == 0) { + char *f, *a; + f = strdup(bg+5); + a = strchr(f, ':'); + if (a) + *a++ = 0; + call5(f, p, 0, pm, a, 0); + free(f); } else pane_clear(p, NULL); if (hdr) { @@ -868,7 +903,7 @@ restart: call_render_line(p, m); } m2 = vmark_next(m); - if (p->cx <= 0 && + if (!hide_cursor && p->cx <= 0 && mark_ordered_or_same_pane(p, m, pm) && (!m2 || mark_ordered_or_same_pane(p, pm, m2))) { int len = call_render_line_to_point(p, pm, @@ -1006,6 +1041,7 @@ DEF_CMD(render_lines_move) struct mark *top; int pagesize = rl->line_height; int scale = get_scale(p); + int ret; top = vmark_first(p, rl->typenum); if (!top) @@ -1014,6 +1050,14 @@ DEF_CMD(render_lines_move) pagesize = p->h - 2 * rl->line_height; rpt *= pagesize; + ret = call3("Presenter-page", p, rpt, ci->mark); + if (ret) { + rl->ignore_point = 0; + find_lines(ci->mark, p); + pane_damaged(p, DAMAGED_CONTENT); + return 10; + } + rl->ignore_point = 1; if (rpt < 0) { @@ -1266,6 +1310,15 @@ DEF_CMD(render_lines_redraw) return 1; } +/* This hack doesn't belong here */ +DEF_CMD(render_lines_display) +{ + if (ci->str && strcmp(ci->str, "refresh") == 0) { + call3("doc:Recentre", ci->focus, 0, ci->mark); + } + return 0; +} + static struct map *rl_map; DEF_LOOKUP_CMD(render_lines_handle, rl_map) @@ -1295,6 +1348,8 @@ static void render_lines_register_map(void) key_add(rl_map, "render-lines:redraw", &render_lines_redraw); key_add(rl_map, "Notify:Replace", &render_lines_notify_replace); + + key_add(rl_map, "Display", &render_lines_display); } REDEF_CMD(render_lines_attach) -- 2.39.5