UI_Markdown.py 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  1. ####################################
  2. # #
  3. # COPYRIGHT NOTICE #
  4. # #
  5. # This file is a part of Victori- #
  6. # ous Children Studio Organizer. #
  7. # Or simply FreeGILE. Copyright #
  8. # of J.Y.Amihud. But don't be sad #
  9. # because I released the entire #
  10. # project under a GNU GPL license. #
  11. # You may use Version 3 or later. #
  12. # See www.gnu.org/licenses if your #
  13. # copy has no License file. Please #
  14. # note. Ones I used the GPL v2 for #
  15. # it. It's no longer the case. #
  16. # #
  17. ####################################
  18. import os
  19. import urllib3
  20. # GTK module ( Graphical interface
  21. import gi
  22. gi.require_version('Gtk', '3.0')
  23. from gi.repository import Gtk
  24. from gi.repository import GLib
  25. from gi.repository import Gdk
  26. import cairo
  27. # Own modules
  28. from settings import settings
  29. from settings import talk
  30. from settings import oscalls
  31. from project_manager import pm_project
  32. #UI modules
  33. from UI import UI_elements
  34. from UI import UI_color
  35. ################################################################################
  36. # Markdown. Or .md file format is an easy way to give your simple text documents
  37. # a bit of flare. Stuff like links, images and quotes are supported. Also bold
  38. # an italic characters.
  39. def Open(win, filename, name):
  40. # This function will parse a Markdown (.md) file into a readable python
  41. # dictionary object. That you can use for various things.
  42. try:
  43. # If the file is local. AKA exists in the folder. And can be read.
  44. # Also it could be not .md
  45. if filename.startswith("lbry://"):
  46. # Sometimes the link is linking an lbry or https source.
  47. # meaning this link is has to be retrieved from the network.
  48. # For this we have to retrieve the data from the network.
  49. # The LBRY protocol has a little serive called spee.ch that
  50. # simply redirects you to the file on the protocol. Let's
  51. # try using it. ( the lbry3.vanwanet.com/speech/ is the
  52. # actuall link it redircts to )
  53. print("LBRY links: "+filename)
  54. filename = filename.replace("lbry://", "https://spee.ch/")
  55. print("REQUESTING: "+filename)
  56. http = urllib3.PoolManager()
  57. resp = http.request('GET', filename)
  58. print("FILE RECIEVED!")
  59. md = resp.data.decode('utf-8')
  60. print("FILE CONVERTED")
  61. elif not filename.endswith(".md"):
  62. 1/0 # Quick fail switch
  63. else:
  64. # Sometimes a language File is provided. let's
  65. # look for it.
  66. l = win.settings["Language"]
  67. if os.path.exists(os.getcwd()+"/"+filename[:-3]+"_"+l+".md"):
  68. filename = filename[:-3]+"_"+l+".md"
  69. md = open(filename)
  70. md = md.read()
  71. except:
  72. # If reading fails. For example if it's a link to something on the
  73. # web. Then try just opening it in the standard application.
  74. md = ""
  75. oscalls.Open(filename)
  76. win.current["mdfs"][name] = win.current["mdfs"]["failsafe"]
  77. # A few things before I gonna make everything. The - [ ] and the - [X] things.
  78. # This is the stuff I want to change to the corresponding icons.
  79. md = md.replace("- [ ]", "![](settings/themes/Default/icons/unchecked.png)")
  80. md = md.replace("- [X]", "![](settings/themes/Default/icons/checked.png)")
  81. md = md.replace("- [x]", "![](settings/themes/Default/icons/checked.png)")
  82. md = md.replace("- ", "• ")
  83. # This one is risky. I want to remove all the ../ so there will not be a
  84. # mistake.
  85. md = md.replace("../", "")
  86. # Spliting it for the read.
  87. md = md.split("\n")
  88. # First thing is I was to read the headings and convert it into a tree.
  89. tree = []
  90. indent = 1
  91. c = []
  92. for line in md:
  93. ty = "text"
  94. te = line
  95. # Here I want to simply get a type of each line. Later we going to parse
  96. # the links and other things. But first. Let's parse stuff based on
  97. # lines.
  98. if line.startswith("#"):
  99. # The titles of the chapter. The Headers are usually written similar
  100. # to how here in python you write comments. It's a # , space, and the
  101. # text.
  102. # The amount of hashes. ## or ### gives different sized text. Officialy
  103. # it should support up to 6 hashes. ######. But why not make it more
  104. # just in case.
  105. ty = line.count("#") # This might give bugs
  106. elif line.startswith("> "):
  107. # The > sign in the Markdown language is used for quatations.
  108. ty = "quote"
  109. tree.append([ty, te+"\n"])
  110. # Now the stage 0 is over and we parsed the basic things. Now is the hard
  111. # part to parse out all the images and stuff inside them. It's going to be
  112. # done per part. And we are going to use the same technique I used for the
  113. # conversion of the legacy projects. See : studio/story.py
  114. # We are going to itterate over each letter. And decide what to do by that
  115. newtree = []
  116. for block in tree:
  117. part = ""
  118. skip = 0
  119. for n, l in enumerate(block[-1]):
  120. if skip > n:
  121. continue
  122. part = part + l
  123. # Here we are going to do something if a give condition is met.
  124. # Usually I gonna do something if [part] ends with a given markdown
  125. # thing. I don't have a mnual of markdown on me. So please make it
  126. # more supported. I guess. I might forget things I rarely use.
  127. # Links are made with [stuff you click on](https://example.com)
  128. # but similar to it. Images are done ![Tooltip](Image.png)
  129. # and even weirder you can put one into the other. Like
  130. # [![Tooltip](Image.png)](https://example.com)
  131. # Which going to give you a clickable image.
  132. # For this version what we are going to do is next.
  133. # If we got [![ then it's a clickable image
  134. # If we got ![ then it's just image
  135. # and if we got [ then it's a link.
  136. if part.endswith("[!["):
  137. # IMAGE LINK
  138. newtree.append([block[0], part[:-3]])
  139. tooltip = ""
  140. imageurl = ""
  141. url = ""
  142. t = False
  143. iu = False
  144. skip = n
  145. for le in block[-1][n:]: # For letters in the rest of text
  146. skip = skip + 1
  147. if le == "]":
  148. t = True
  149. elif le == ")" and t and not iu:
  150. iu = True
  151. elif le == ")" and t and iu:
  152. break
  153. elif not t:
  154. tooltip = tooltip +le
  155. elif t and not iu:
  156. imageurl = imageurl + le
  157. else:
  158. url = url+le
  159. tooltip = tooltip[tooltip.find("[")+1:]
  160. imageurl = imageurl[imageurl.find("(")+1:]
  161. url = url[url.find("(")+1:]
  162. apnd = ["image_link", tooltip, imageurl, url]
  163. newtree.append(apnd)
  164. part = ""
  165. elif part.endswith("!["):
  166. # IMAGE
  167. newtree.append([block[0], part[:-2]])
  168. tooltip = ""
  169. url = ""
  170. t = False
  171. skip = n
  172. for le in block[-1][n:]: # For letters in the rest of text
  173. skip = skip + 1
  174. if le == "]":
  175. t = True
  176. elif le == ")" and t:
  177. break
  178. elif not t:
  179. tooltip = tooltip +le
  180. else:
  181. url = url+le
  182. tooltip = tooltip[tooltip.find("[")+1:]
  183. url = url[url.find("(")+1:]
  184. apnd = ["image", tooltip, url]
  185. newtree.append(apnd)
  186. part = ""
  187. elif part.endswith("[") and not block[-1][n:].startswith('[!['):
  188. # LINK
  189. newtree.append([block[0], part[:-1]])
  190. tooltip = ""
  191. url = ""
  192. t = False
  193. skip = n
  194. for le in block[-1][n:]: # For letters in the rest of text
  195. skip = skip + 1
  196. if le == "]":
  197. t = True
  198. elif le == ")" and t:
  199. break
  200. elif not t:
  201. tooltip = tooltip +le
  202. else:
  203. url = url+le
  204. tooltip = tooltip[tooltip.find("[")+1:]
  205. url = url[url.find("(")+1:]
  206. apnd = ["link", tooltip, url]
  207. newtree.append(apnd)
  208. part = ""
  209. # Now I want to deal with `, *, ** and ***. If you want to help me you
  210. # can implement other types. Such as _, __, ___ and so on. Markdown is
  211. # a very rich language. I'm going to use the cut down version I see other
  212. # people use.
  213. # BTW this is the time. Feb 28. When I switched from Gedit to GNU Emacs.
  214. # Interesting feeling using this programm. I kind a love it even tho
  215. # so many stuff in not intuitive. Like saving is not Ctrl - S but
  216. # Ctrl - X -> Ctrl - S.
  217. # Things like Alt-; to comment multiple lines at ones is HUGE. Also it
  218. # was built by programmers for programmers. So it's a very good tool.
  219. elif part.endswith("**") and not block[-1][n+2:].startswith('*'):
  220. # DOUBLE **
  221. newtree.append([block[0], part[:-2]])
  222. if block[0] == "text":
  223. block[0] = "text_b"
  224. else:
  225. block[0] = "text"
  226. part = ""
  227. elif part.endswith("*") and not block[-1][n+1:].startswith('*'):
  228. # SINGLE *
  229. newtree.append([block[0], part[:-1]])
  230. if block[0] == "text":
  231. block[0] = "text_i"
  232. else:
  233. block[0] = "text"
  234. part = ""
  235. elif part.endswith("`"):
  236. # SINGLE `
  237. newtree.append([block[0], part[:-1]])
  238. if block[0] == "text":
  239. block[0] = "text_c"
  240. else:
  241. block[0] = "text"
  242. part = ""
  243. newtree.append([block[0], part])
  244. tree = newtree
  245. return(tree)
  246. def search_convert(s):
  247. # This function convers a chapter name into a link
  248. # such links are use in notabug.org to link to chapters
  249. # for example example.com/file.md#chapter-name
  250. # With this url it will load the example.com/file.md and
  251. # then skip to the "Chapter Name" chapter.
  252. # This function transforms "Chapter Name" into "chapter-name"
  253. l = " ./\|[]{}()?!@#$%^&*`~:;'\"=,<>"
  254. s = s.lower().replace(" ","-")
  255. r = ""
  256. for i in s:
  257. if i not in l:
  258. r = r + i
  259. return r
  260. def draw(outlayer, win, name, x, y, width, height):
  261. # Now you maybe woundering where is the filname to read from. Well. We are
  262. # making it now.
  263. if "mdfs" not in win.current:
  264. win.current["mdfs"] = {}
  265. win.current["mdfs"]["failsafe"] = ""
  266. if name not in win.current["mdfs"]:
  267. win.current["mdfs"][name] = ""
  268. filename = win.current["mdfs"][name]
  269. filename = filename.replace("../", "")
  270. win.current["mdfs"][name] = filename
  271. # The # sing usually calls for search with in the text.
  272. if "#" in filename and not "@" in filename:
  273. filename, search = filename.split("#")
  274. win.current["mdfs"][name] = filename
  275. else:
  276. search = ""
  277. # First we don't want to waste resources to parse the file on each frame
  278. # so let's load it ones.
  279. if "mds" not in win.current:
  280. win.current["mds"] = {}
  281. if filename not in win.current["mds"]:
  282. win.current["mds"][filename] = Open(win, filename, name)
  283. md = win.current["mds"][filename]
  284. # This peace of code outputs the parsed object into terminal for reading.
  285. # for i in md:
  286. # if type(i) == str:
  287. # print("'"+i+"' ,")
  288. # else:
  289. # print(i, ",")
  290. # Background
  291. UI_color.set(outlayer, win, "node_background")
  292. UI_elements.roundrect(outlayer, win,
  293. x,
  294. y,
  295. width,
  296. height,
  297. 10)
  298. outlayer.fill()
  299. # The name of the file first. I think it's gonna make sense to make it in
  300. # an entry. So people could insert any filename, or link in future.
  301. try:
  302. UI_elements.text(outlayer, win, "markdown_name",
  303. x+10,
  304. y+5,
  305. int(width/2)-120,
  306. 40,
  307. set_text=filename,
  308. fill=False)
  309. if win.text["markdown_name"]["text"] != filename \
  310. and win.textactive != "markdown_name":
  311. win.text["markdown_name"]["text"] = filename
  312. # Let me make it user editable as well. Because I'm a nerd
  313. # and I want to see how it handles various problems.
  314. elif win.text["markdown_name"]["text"] != filename:
  315. def do():
  316. win.current["mdfs"]["failsafe"] = filename
  317. win.current["mdfs"][name] = win.text["markdown_name"]["text"]
  318. UI_elements.roundrect(outlayer, win,
  319. x+int(width/2)-150,
  320. y+5,
  321. 40,
  322. 40,
  323. 10,
  324. button=do,
  325. icon="ok",
  326. tip=talk.text("checked"))
  327. except:
  328. pass
  329. # Users should be able to chose whether automatic downloading of stuff
  330. # will be done by the software. This is why I want to add this setting
  331. # here too. And not barried somewhere in the settings.
  332. if width > 350:
  333. download_ok = "unchecked"
  334. if win.settings["auto_download_images"]:
  335. download_ok = "checked"
  336. def do():
  337. win.settings["auto_download_images"] = not win.settings["auto_download_images"]
  338. settings.write("auto_download_images", win.settings["auto_download_images"])
  339. UI_elements.roundrect(outlayer, win,
  340. x+int(width/2)-100,
  341. y+5,
  342. int(width/2)-150,
  343. 40,
  344. 10,
  345. button=do,
  346. icon=download_ok,
  347. tip=talk.text("auto_download_images"))
  348. UI_color.set(outlayer, win, "text_normal")
  349. outlayer.set_font_size(20)
  350. outlayer.move_to(x+int(width/2)-50,
  351. y+30)
  352. outlayer.show_text(talk.text("auto_download_images")[:int((int(width/2)-150)/9)])
  353. # I want to include 2 button to the top raw besides the adress bar.
  354. # A button to open the file in the standard application. ( Edit )
  355. # A button to open the NoABug repository version ( NotABug )
  356. if width > 150 and not filename.startswith("lbry://"):
  357. # EDIT
  358. def do():
  359. oscalls.Open(filename)
  360. UI_elements.roundrect(outlayer, win,
  361. x+int(width)-100,
  362. y+5,
  363. 40,
  364. 40,
  365. 10,
  366. button=do,
  367. icon="edit",
  368. tip=talk.text("edit_markdown"))
  369. # NOTABUG
  370. def do():
  371. oscalls.Open("https://notabug.org/troler/FreeGILE/src/master/"+filename)
  372. UI_elements.roundrect(outlayer, win,
  373. x+int(width)-50,
  374. y+5,
  375. 40,
  376. 40,
  377. 10,
  378. button=do,
  379. icon="notabug",
  380. tip=talk.text("notabug_markdown"))
  381. elif width > 100:
  382. # ODYSEE ( LBRY ) open in browser
  383. def do():
  384. oscalls.Open(filename.replace("lbry://", "https://odysee.com/"))
  385. UI_elements.roundrect(outlayer, win,
  386. x+int(width)-50,
  387. y+5,
  388. 40,
  389. 40,
  390. 10,
  391. button=do,
  392. icon="lbry",
  393. tip="Odysee.com (LBRY)")
  394. # Now let's draw the bastard. We are going to do it the same way as in the
  395. # script writer. But rather simplified. For example we are not making an
  396. # editor. But only a reader. So we don't need the selection. And we don't
  397. # need to calculate every letter preciselly. With something like codes
  398. # I can do that every ` object will be drawn in a text entry object. Why
  399. # not.
  400. # I need to make a new Layer because we are going to clip it for the text.
  401. textsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
  402. layer = cairo.Context(textsurface)
  403. layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
  404. layer_i = cairo.Context(textsurface)
  405. layer_i.select_font_face("Monospace", cairo.FONT_SLANT_ITALIC, cairo.FONT_WEIGHT_NORMAL)
  406. layer_b = cairo.Context(textsurface)
  407. layer_b.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
  408. layer_bi = cairo.Context(textsurface)
  409. layer_bi.select_font_face("Monospace", cairo.FONT_SLANT_ITALIC, cairo.FONT_WEIGHT_BOLD)
  410. UI_elements.roundrect(layer, win, 0,50,width, height-50, 10,fill=False)
  411. layer.clip()
  412. UI_elements.roundrect(layer_b, win, 0,50,width, height-50, 10,fill=False)
  413. layer_b.clip()
  414. UI_elements.roundrect(layer_bi, win, 0,50,width, height-50, 10,fill=False)
  415. layer_bi.clip()
  416. UI_elements.roundrect(layer_i, win, 0,50,width, height-50, 10,fill=False)
  417. layer_i.clip()
  418. ############################################################################
  419. # HERE WE DRAWING TEXT TO THE SCREEN #
  420. ############################################################################
  421. if "markdown" not in win.scroll:
  422. win.scroll["markdown"] = 0
  423. current_Y = 70
  424. tyleX = 10
  425. newX = 10
  426. newY = 0
  427. for block in md:
  428. # THE # HEADERS
  429. if type(block[0]) == int:
  430. current_Y = current_Y + newY + 100
  431. UI_color.set(layer_b, win, "text_normal")
  432. layer_b.set_font_size(30-(block[0]*4))
  433. layer_b.move_to(
  434. 10,
  435. current_Y + win.scroll["markdown"]
  436. )
  437. layer_b.show_text(block[1].replace("\n", "").replace("#", " "))
  438. current_Y = current_Y + 40
  439. if search and search in search_convert(block[1].replace("\n", "").replace("#", "")):
  440. win.scroll["markdown"] = 0 - current_Y + 140
  441. search = ""
  442. newX = 10
  443. newY = 0
  444. # IMAGES
  445. # This going to be hard. I have an interesting idea about it.
  446. # 1.) Make the images whos links are in the internet loadable.
  447. # This will require some clever thinking. Because not all
  448. # users want to automatically download images from a source
  449. # that they don't trust. I'm hosting most of the images
  450. # at the moment on NotABug.org with the project's code.
  451. # But. That I trust it. Doesn't mean everybody trust it
  452. # or should trust it. So Downloading of images should be
  453. # optional. We can make a button to download a given image
  454. # and a setting in the settings to download them automatically.
  455. #
  456. # Now thinking about it. The Update system should use something
  457. # similar.
  458. #
  459. # 2.) Warping of text around the image. This is something original
  460. # markdown not really supports. On NotABug the images in the text
  461. # look a bit ugly because they stretch the line height.
  462. # I propose using a kind of warp around system. Let me demonstrate.
  463. # ############### This is a sample text about the Image.png. That
  464. # # # is going to warp around the image like so.
  465. # # Image.png # More text is needed to show the extent of this
  466. # # # effect. So I'm going to ramble about something.
  467. # # # Hello World! Are you a true hacker? I hope you
  468. # ############### are. And not a cracker. Now see what's going to
  469. # happen when the image is ended. The next line is written under
  470. # the image. Which is a cool look. Now ...
  471. # I have no idea what to do if the image is going to be rendered in
  472. # the middle of the paragraph. Maybe the image in the middle should
  473. # act like in a normal implementation. And only at the start as
  474. # what I showed you now.
  475. elif "image" in block[0]:
  476. # ICONS
  477. # Sometimes I link Icons from OldSchool theme to the text. They
  478. # look good on a white background in the NotABug.org page.
  479. # But. Since they are icons that might have different themes for
  480. # the users let's make them theme respecting.
  481. if "settings/themes/" in block[2] and "/icons/" in block[2]:
  482. iconname = block[2][block[2].rfind('/')+1:]
  483. block[2] = "settings/themes/"+win.settings["Theme"]+"/icons/"+iconname
  484. UI_elements. image(layer, win, "settings/themes/"\
  485. +win.settings["Theme"]+"/icons/"+iconname,
  486. tyleX,
  487. current_Y + win.scroll["markdown"]-30)
  488. tyleX = tyleX + 40
  489. # OTHER IMAGES
  490. # I think the handling of the images loading should be done in the
  491. # UI_elements.py file. So I could easy reimplement this feature
  492. # else where.
  493. else:
  494. if newY:
  495. current_Y = current_Y + newY + 40
  496. tyleX = 10
  497. newX = 10
  498. newY = 0
  499. UI_elements. image(layer, win, block[2],
  500. tyleX,
  501. current_Y + win.scroll["markdown"]-15,
  502. cell="markdown",offset=[x,y],width=width-40,fit="fit_width")
  503. try:
  504. imH = win.images["markdown"][block[2]]['image'].get_height()
  505. imW = win.images["markdown"][block[2]]['image'].get_width()
  506. except:
  507. imH = 40
  508. imW = 40
  509. bx = tyleX
  510. by = current_Y
  511. if imW < width/2:
  512. tyleX = tyleX + imW
  513. newX = imW + 40
  514. newY = imH - 20
  515. else:
  516. tyleX = 10
  517. current_Y = current_Y + imH
  518. # LINKED IMAGES
  519. if "link" in block[0]:
  520. # If the image is linked. We are going to separate it in 2 categoies.
  521. # If automatic downloading is on. There is no difference. Else. There
  522. # will be a difference. Since the image from the Internet going to be
  523. # a button to download it. We need to offset the link button. SO.
  524. def do():
  525. if block[3].endswith(".md"):
  526. win.current["mdfs"]["failsafe"] = filename
  527. win.current["mdfs"][name] = block[3]
  528. win.current["current_help_selected"] = ""
  529. win.scroll["markdown"] = 0
  530. else:
  531. oscalls.Open(block[3])
  532. try:
  533. downloadbutton = win.images["markdown"][block[2]]["image"] == "download_button"
  534. except:
  535. downloadbutton = False
  536. if not win.settings["auto_download_images"]\
  537. and block[2].startswith("http")\
  538. and downloadbutton:
  539. # Here goes the offsetted link.
  540. UI_elements.roundrect(layer, win, tyleX,
  541. current_Y + win.scroll["markdown"]-15,40,40,10,
  542. icon="internet",
  543. button=do,
  544. offset=[x,y],
  545. tip=block[3])
  546. tyleX = tyleX + 60
  547. else:
  548. # Full on image
  549. UI_elements.roundrect(layer, win, bx,
  550. by + win.scroll["markdown"]-15,imW, imH,10,
  551. button=do,
  552. offset=[x,y],
  553. tip=block[3],
  554. fill=False)
  555. layer.stroke()
  556. # TEXT
  557. elif block[0] in ["text", "text_i", "text_b", "text_ib", "text_c", "link"]:
  558. for word in block[1].split(" "):
  559. if tyleX + len(word)*12+12 > width :
  560. tyleX = newX
  561. newY = max(0, newY-30)
  562. if newY == 0:
  563. newX = 10
  564. current_Y = current_Y + 30
  565. # Any type of Text. Whether it's Normal, Bold or Italic gonna
  566. # have the same color.
  567. if "text" in block[0]:
  568. UI_color.set(layer, win, "text_normal")
  569. UI_color.set(layer_i, win, "text_normal")
  570. UI_color.set(layer_b, win, "text_normal")
  571. UI_color.set(layer_bi, win, "text_normal")
  572. # Unless it's a link. Then I have a special color for it in the
  573. # theme. I tried reusing pre-existing. Non of them works across
  574. # multiple themes.
  575. else:
  576. # Here I gonna introduce the logic of the links. Because
  577. # I'm lazy.
  578. if "markdown_mouse_link" not in win.current:
  579. win.current["markdown_mouse_link"] = ""
  580. if win.current["mx"] in range(int(x+tyleX-6), int(x+tyleX-6+len(word)*12+12))\
  581. and win.current["my"] in range(int(y+current_Y + win.scroll["markdown"]-20),
  582. int(y+current_Y + win.scroll["markdown"]+5)):
  583. win.current["markdown_mouse_link"] = block[2]
  584. UI_elements.tooltip(win,block[2])
  585. # AHh... I'll do a clicker here.
  586. if not win.current["LMB"] and win.previous["LMB"]:
  587. if block[2].startswith("#"):
  588. win.current["mdfs"][name] = win.current["mdfs"][name] + block[2]
  589. win.current["current_help_selected"] = ""
  590. else:
  591. win.current["mdfs"]["failsafe"] = filename
  592. win.current["mdfs"][name] = block[2]
  593. win.current["current_help_selected"] = ""
  594. win.scroll["markdown"] = 0
  595. elif win.current["mx"] not in range(win.previous["mx"]-5, win.previous["mx"]+5):
  596. win.current["markdown_mouse_link"] = ""
  597. # If mouse hovering over a link. Draw a line under the link.
  598. if win.current["markdown_mouse_link"] == block[2]:
  599. UI_color.set(layer, win, "text_normal")
  600. UI_elements.roundrect(layer, win,
  601. tyleX-6,
  602. current_Y + win.scroll["markdown"],
  603. len(word)*12+12,
  604. 4,
  605. 2)
  606. UI_color.set(layer, win, "text_link")
  607. # Italic text
  608. if "_i" in block[0]:
  609. layer_i.set_font_size(20)
  610. layer_i.move_to(
  611. tyleX,
  612. current_Y + win.scroll["markdown"]
  613. )
  614. layer_i.show_text(word.replace("\n", ""))
  615. # Bold text
  616. elif "_b" in block[0]:
  617. layer_b.set_font_size(20)
  618. layer_b.move_to(
  619. tyleX,
  620. current_Y + win.scroll["markdown"]
  621. )
  622. layer_b.show_text(word.replace("\n", ""))
  623. # Any other text
  624. else:
  625. if "_c" in block[0]:
  626. UI_color.set(layer, win, "node_background")
  627. UI_elements.roundrect(layer, win,
  628. tyleX-6,
  629. current_Y + win.scroll["markdown"]-20,
  630. len(word)*12+12,
  631. 25,
  632. 5)
  633. UI_color.set(layer, win, "text_normal")
  634. layer.set_font_size(20)
  635. layer.move_to(
  636. tyleX,
  637. current_Y + win.scroll["markdown"]
  638. )
  639. layer.show_text(word.replace("\n", ""))
  640. # Moving of to the next word.
  641. if "\n" in word:
  642. tyleX = newX
  643. newY = max(0, newY-30)
  644. if newY == 0:
  645. newX = 10
  646. current_Y = current_Y + 30
  647. else:
  648. tyleX = tyleX + len(word)*12+12
  649. ############################################################################
  650. # #########################################
  651. # BEFORE WE GONNA END THE DRAWING OF THE
  652. # MARKDOWN. IF IT'S UPDATE INFORMATION WE
  653. # NEED TO GET THE USER A LIST OF FILES WITH
  654. # 2 BUTTONS. TO OPEN, TO VIEW IN NOTABUG
  655. # AND TO SEE HISTORY.
  656. # #########################################
  657. if "update_markdown_files" in win.current:
  658. files = win.current["update_markdown_files"]
  659. tyleX = 50
  660. for file in files:
  661. if int(current_Y + win.scroll["markdown"] + 100) in range(0-100, win.current["h"]):
  662. # Making the layer
  663. nodesurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 170, 250)
  664. node = cairo.Context(nodesurface)
  665. node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
  666. UI_elements.roundrect(node, win,
  667. 0,
  668. 0,
  669. 170,
  670. 250,
  671. 10,
  672. fill=False)
  673. node.clip()
  674. # Background
  675. UI_color.set(node, win, "dark_overdrop")
  676. node.rectangle(0,0,170, 250)
  677. node.fill()
  678. # Banner
  679. UI_color.set(node, win, "node_asset")
  680. node.rectangle(0,0,170, 20)
  681. node.fill()
  682. # Outputting the layer
  683. layer.set_source_surface(nodesurface,
  684. tyleX-10,
  685. current_Y + win.scroll["markdown"] + 120)
  686. layer.paint()
  687. # ICON
  688. UI_elements.image(layer, win, file,
  689. tyleX,
  690. current_Y + win.scroll["markdown"] + 140,
  691. 150,
  692. 150,
  693. cell="update_previews")
  694. # NAME
  695. UI_color.set(layer, win, "text_normal")
  696. layer.set_font_size(12)
  697. layer.move_to(tyleX,
  698. current_Y + win.scroll["markdown"] + 135)
  699. layer.show_text(file[file.rfind("/")+1:][:22])
  700. # BUTTON
  701. def do():
  702. win.current["mdfs"]["failsafe"] = filename
  703. win.current["mdfs"][name] = file
  704. win.current["update_markdown_files"] = []
  705. layer.set_line_width(4)
  706. UI_elements.roundrect(layer, win,
  707. tyleX-10,
  708. current_Y + win.scroll["markdown"] + 120,
  709. 170,
  710. 200,
  711. 10,
  712. button=do,
  713. tip=file,
  714. fill=False,
  715. offset=[x,y])
  716. layer.stroke()
  717. layer.set_line_width(2)
  718. # Two buttons for notabug version and history of the file
  719. ntbg = "https://notabug.org/troler/FreeGILE/src/master/"
  720. def do():
  721. oscalls.Open(ntbg+file)
  722. UI_elements.roundrect(layer, win,
  723. tyleX+35,
  724. current_Y + win.scroll["markdown"] + 120+205,
  725. 40,
  726. 40,
  727. 10,
  728. button=do,
  729. tip=ntbg+file,
  730. icon="notabug",
  731. offset=[x,y])
  732. ntbg = "https://notabug.org/troler/FreeGILE/commits/master/"
  733. def do():
  734. oscalls.Open(ntbg+file)
  735. UI_elements.roundrect(layer, win,
  736. tyleX+75,
  737. current_Y + win.scroll["markdown"] + 120+205,
  738. 40,
  739. 40,
  740. 10,
  741. button=do,
  742. tip=ntbg+file,
  743. icon="history",
  744. offset=[x,y])
  745. tyleX = tyleX + 200
  746. if tyleX > width-210:
  747. tyleX = 50
  748. current_Y = current_Y + 270
  749. current_Y = current_Y + 400
  750. # Scroll
  751. UI_elements.scroll_area(outlayer, win, "markdown",
  752. x+0,
  753. y+0,
  754. width+30,
  755. height-0,
  756. current_Y,
  757. bar=True,
  758. mmb=True,
  759. strenght=300,
  760. bar_always=True)
  761. # Outputting the layer
  762. outlayer.set_source_surface(textsurface, x, y)
  763. outlayer.paint()