d.frame.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #!/usr/bin/env python
  2. ############################################################################
  3. #
  4. # MODULE: d.frame
  5. # AUTHOR(S): Martin Landa <landa.martin gmail.com>
  6. # Based on d.frame from GRASS 6
  7. # PURPOSE: Manages display frames on the user's graphics monitor
  8. # COPYRIGHT: (C) 2014-2015 by Martin Landa, and the GRASS Development Team
  9. #
  10. # This program is free software; you can redistribute it and/or modify
  11. # it under the terms of the GNU General Public License as published by
  12. # the Free Software Foundation; either version 2 of the License, or
  13. # (at your option) any later version.
  14. #
  15. # This program is distributed in the hope that it will be useful,
  16. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. # GNU General Public License for more details.
  19. #
  20. ############################################################################
  21. #%module
  22. #% description: Manages display frames on the user's graphics monitor.
  23. #% keyword: display
  24. #% keyword: graphics
  25. #% keyword: monitors
  26. #% keyword: frame
  27. #% overwrite: yes
  28. #%end
  29. #%flag
  30. #% key: c
  31. #% description: Create a new frame if doesn't exist and select
  32. #%end
  33. #%flag
  34. #% key: e
  35. #% description: Remove all frames, erase the screen and exit
  36. #% suppress_required: yes
  37. #%end
  38. #%flag
  39. #% key: p
  40. #% description: Print name of current frame and exit
  41. #% suppress_required: yes
  42. #%end
  43. #%flag
  44. #% key: a
  45. #% description: Print names of all frames including 'at' position and exit
  46. #% suppress_required: yes
  47. #%end
  48. #%option
  49. #% key: frame
  50. #% type: string
  51. #% required: yes
  52. #% multiple: no
  53. #% key_desc: name
  54. #% description: Frame to be selected or created (if -c flag is given)
  55. #%end
  56. #%option
  57. #% key: at
  58. #% type: double
  59. #% required: no
  60. #% multiple: no
  61. #% key_desc: bottom,top,left,right
  62. #% label: Screen coordinates in percent where to place the frame (0,0 is lower-left)
  63. #% options: 0-100
  64. #% description: Implies only when -c or --overwrite flag is given
  65. #%end
  66. import os
  67. import sys
  68. from grass.script.core import parser, read_command, fatal, debug, run_command, gisenv, warning, parse_command
  69. # check if monitor is running
  70. def check_monitor():
  71. return read_command('d.mon', flags='p', quiet=True).strip()
  72. # read monitor file and return list of lines
  73. # TODO: replace by d.info (see #2577)
  74. def read_monitor_file(monitor, ftype='env'):
  75. mfile = check_monitor_file(monitor, ftype)
  76. try:
  77. fd = open(mfile, 'r')
  78. except IOError as e:
  79. fatal(_("Unable to get monitor info. %s"), e)
  80. lines = []
  81. for line in fd.readlines():
  82. lines.append(line)
  83. fd.close()
  84. return lines
  85. # check if monitor file exists
  86. def check_monitor_file(monitor, ftype='env'):
  87. mfile = parse_command('d.mon', flags='g').get(ftype, None)
  88. if mfile is None or not os.path.isfile(mfile):
  89. fatal(_("Unable to get monitor info (no %s found)") % var)
  90. return mfile
  91. # write new monitor file
  92. def write_monitor_file(monitor, lines, ftype='env'):
  93. mfile = check_monitor_file(monitor, ftype)
  94. try:
  95. fd = open(mfile, 'w')
  96. except IOError as e:
  97. fatal(_("Unable to get monitor info. %s"), e)
  98. fd.writelines(lines)
  99. fd.close()
  100. # remove all frames and erase screen
  101. def erase(monitor):
  102. # remove frames
  103. lines = []
  104. for line in read_monitor_file(monitor):
  105. if 'FRAME' not in line:
  106. lines.append(line)
  107. write_monitor_file(monitor, lines)
  108. # erase screen
  109. run_command('d.erase')
  110. # find frame for given monitor
  111. def find_frame(monitor, frame):
  112. for line in read_monitor_file(monitor):
  113. if 'FRAME' in line:
  114. if get_frame_name(line) == frame:
  115. return True
  116. return False
  117. # print frames name(s) to stdout
  118. def print_frames(monitor, current_only=False, full=False):
  119. for line in read_monitor_file(monitor):
  120. if 'FRAME' not in line:
  121. continue
  122. if current_only and line.startswith('#'):
  123. continue
  124. sys.stdout.write(get_frame_name(line))
  125. if full:
  126. sys.stdout.write(':' + line.split('=', 1)[1].rsplit('#', 1)[0])
  127. sys.stdout.write('\n')
  128. # get frame name from line
  129. def get_frame_name(line):
  130. return line.rstrip('\n').rsplit('#', 1)[1].strip(' ')
  131. # calculate position of the frame in percent
  132. def calculate_frame(frame, at, width, height):
  133. try:
  134. b, t, l, r = map(float, at.split(','))
  135. except:
  136. fatal(_("Invalid frame position: %s") % at)
  137. top = height - (t / 100. * height)
  138. bottom = height - (b / 100. * height)
  139. left = l / 100. * width
  140. right = r / 100. * width
  141. return 'GRASS_RENDER_FRAME=%d,%d,%d,%d # %s%s' % \
  142. (top, bottom, left, right, frame, '\n')
  143. # create new frame
  144. def create_frame(monitor, frame, at, overwrite=False):
  145. lines = read_monitor_file(monitor)
  146. # get width and height of the monitor
  147. width = height = -1
  148. for line in lines:
  149. try:
  150. if 'WIDTH' in line:
  151. width = int(line.split('=', 1)[1].rsplit(' ', 1)[0])
  152. elif 'HEIGHT' in line:
  153. height = int(line.split('=', 1)[1].rsplit(' ', 1)[0])
  154. except:
  155. pass
  156. if width < 0 or height < 0:
  157. fatal(_("Invalid monitor size: %dx%d") % (width, height))
  158. if not overwrite:
  159. lines.append(calculate_frame(frame, at, width, height))
  160. else:
  161. for idx in range(len(lines)):
  162. line = lines[idx]
  163. if 'FRAME' not in line:
  164. continue
  165. if get_frame_name(line) == frame:
  166. lines[idx] = calculate_frame(frame, at, width, height)
  167. write_monitor_file(monitor, lines)
  168. # select existing frame
  169. def select_frame(monitor, frame):
  170. lines = read_monitor_file(monitor)
  171. for idx in range(len(lines)):
  172. line = lines[idx]
  173. if 'FRAME' not in line:
  174. continue
  175. if get_frame_name(line) == frame:
  176. if line.startswith('#'):
  177. lines[idx] = line.lstrip('# ') # un-comment line
  178. elif not line.startswith('#'):
  179. lines[idx] = '# ' + line # comment-line
  180. write_monitor_file(monitor, lines)
  181. def main():
  182. # get currently selected monitor
  183. monitor = check_monitor()
  184. if not monitor:
  185. fatal(_("No graphics device selected. Use d.mon to select graphics device."))
  186. if flags['e']:
  187. # remove frames and erase monitor and exit
  188. erase(monitor)
  189. return
  190. if flags['p']:
  191. # print current frame and exit
  192. print_frames(monitor, current_only=True)
  193. return
  194. if flags['a']:
  195. # print all frames including their position and exit
  196. print_frames(monitor, current_only=False, full=True)
  197. return
  198. found = find_frame(monitor, options['frame'])
  199. if not found:
  200. if not flags['c']:
  201. fatal(_("Frame <%s> doesn't exist, exiting. "
  202. "To create a new frame use '-c' flag.") % options['frame'])
  203. else:
  204. if not options['at']:
  205. fatal(_("Required parameter <%s> not set") % "at")
  206. # create new frame if not exists
  207. create_frame(monitor, options['frame'], options['at'])
  208. else:
  209. if os.getenv('GRASS_OVERWRITE', '0') == '1':
  210. warning(_("Frame <%s> already exists and will be overwritten") % options['frame'])
  211. create_frame(monitor, options['frame'], options['at'], overwrite=True)
  212. else:
  213. if options['at']:
  214. warning(_("Frame <%s> already found. An existing frame can be overwritten by '%s' flag.") % \
  215. (options['frame'], "--overwrite"))
  216. # select givenframe
  217. select_frame(monitor, options['frame'])
  218. if __name__ == "__main__":
  219. options, flags = parser()
  220. sys.exit(main())