coreui.c 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291
  1. /*
  2. * BURG - Brand-new Universal loadeR from GRUB
  3. * Copyright 2009 Bean Lee - All Rights Reserved
  4. *
  5. * BURG is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * BURG is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with BURG. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/dl.h>
  19. #include <grub/mm.h>
  20. #include <grub/misc.h>
  21. #include <grub/term.h>
  22. #include <grub/widget.h>
  23. #include <grub/lib.h>
  24. #include <grub/bitmap_scale.h>
  25. #include <grub/menu_data.h>
  26. #include <grub/parser.h>
  27. #include <grub/lib.h>
  28. #include <grub/charset.h>
  29. #include <grub/trig.h>
  30. #define MARGIN_FINI 0
  31. #define MARGIN_WIDTH 1
  32. #define MARGIN_HEIGHT 2
  33. static void
  34. adjust_margin (grub_widget_t widget, const char *name, int mode)
  35. {
  36. char buf[20], *p;
  37. int len, size;
  38. grub_strcpy (buf, name);
  39. len = grub_strlen (buf);
  40. buf[len++] = '_';
  41. grub_strcpy (&buf[len], "size");
  42. p = grub_widget_get_prop (widget->node, buf);
  43. size = (p) ? grub_menu_parse_size (p, 0, 1) : 0;
  44. if (mode != MARGIN_HEIGHT)
  45. {
  46. int v;
  47. grub_strcpy (&buf[len], "left");
  48. p = grub_widget_get_prop (widget->node, buf);
  49. v = (p) ? grub_menu_parse_size (p, 0, 1) : size;
  50. if (mode == MARGIN_FINI)
  51. {
  52. widget->inner_x += v;
  53. widget->inner_width -= v;
  54. }
  55. else
  56. widget->width += v;
  57. grub_strcpy (&buf[len], "right");
  58. p = grub_widget_get_prop (widget->node, buf);
  59. v = (p) ? grub_menu_parse_size (p, 0, 1) : size;
  60. if (mode == MARGIN_FINI)
  61. widget->inner_width -= v;
  62. else
  63. widget->width += v;
  64. }
  65. if (mode != MARGIN_WIDTH)
  66. {
  67. int v;
  68. grub_strcpy (&buf[len], "top");
  69. p = grub_widget_get_prop (widget->node, buf);
  70. v = (p) ? grub_menu_parse_size (p, 0, 0) : size;
  71. if (mode == MARGIN_FINI)
  72. {
  73. widget->inner_y += v;
  74. widget->inner_height -= v;
  75. }
  76. else
  77. widget->height += v;
  78. grub_strcpy (&buf[len], "bottom");
  79. p = grub_widget_get_prop (widget->node, buf);
  80. v = (p) ? grub_menu_parse_size (p, 0, 0) : size;
  81. if (mode == MARGIN_FINI)
  82. widget->inner_height -= v;
  83. else
  84. widget->height += v;
  85. }
  86. }
  87. static grub_menu_region_common_t
  88. get_bitmap (grub_widget_t widget, const char *name,
  89. int fallback, grub_menu_region_common_t *bitmap_selected)
  90. {
  91. char *p;
  92. p = grub_widget_get_prop (widget->node, name);
  93. return grub_menu_parse_bitmap (p, (fallback) ? 0 : -1, bitmap_selected);
  94. }
  95. struct screen_data
  96. {
  97. grub_menu_region_common_t background;
  98. };
  99. static int
  100. screen_get_data_size (void)
  101. {
  102. return sizeof (struct screen_data);
  103. }
  104. static void
  105. screen_init_size (grub_widget_t widget)
  106. {
  107. struct screen_data *data = widget->data;
  108. data->background = get_bitmap (widget, "background", 1, 0);
  109. grub_menu_region_get_screen_size (&widget->width, &widget->height);
  110. grub_menu_region_scale (data->background, widget->width, widget->height);
  111. }
  112. static void
  113. screen_fini_size (grub_widget_t widget)
  114. {
  115. adjust_margin (widget, "margin", MARGIN_FINI);
  116. }
  117. static void
  118. screen_free (grub_widget_t widget)
  119. {
  120. struct screen_data *data = widget->data;
  121. grub_menu_region_free (data->background);
  122. }
  123. static void
  124. screen_draw (grub_widget_t widget, grub_menu_region_update_list_t *head,
  125. int x, int y, int width, int height)
  126. {
  127. struct screen_data *data = widget->data;
  128. grub_menu_region_add_update (head, data->background,
  129. widget->org_x, widget->org_y,
  130. x, y, width, height);
  131. }
  132. static struct grub_widget_class screen_widget_class =
  133. {
  134. .name = "screen",
  135. .get_data_size = screen_get_data_size,
  136. .init_size = screen_init_size,
  137. .fini_size = screen_fini_size,
  138. .free = screen_free,
  139. .draw = screen_draw
  140. };
  141. #define INDEX_TOP_LEFT 0
  142. #define INDEX_TOP 1
  143. #define INDEX_TOP_RIGHT 2
  144. #define INDEX_LEFT 3
  145. #define INDEX_RIGHT 4
  146. #define INDEX_BOTTOM_LEFT 5
  147. #define INDEX_BOTTOM 6
  148. #define INDEX_BOTTOM_RIGHT 7
  149. #define INDEX_BACKGROUND 8
  150. #define INDEX_SELECTED 9
  151. #define INDEX_BORDER_TOP 18
  152. #define INDEX_BORDER_LEFT 19
  153. #define INDEX_BORDER_RIGHT 20
  154. #define INDEX_BORDER_BOTTOM 21
  155. #define INDEX_COUNT 22
  156. struct panel_data
  157. {
  158. grub_menu_region_common_t bitmaps[INDEX_COUNT];
  159. grub_video_color_t color;
  160. grub_video_color_t color_selected;
  161. grub_uint32_t fill;
  162. grub_uint32_t fill_selected;
  163. };
  164. static char *border_names[8] =
  165. {
  166. "top_left",
  167. "top",
  168. "top_right",
  169. "left",
  170. "right",
  171. "bottom_left",
  172. "bottom",
  173. "bottom_right"
  174. };
  175. static int
  176. panel_get_data_size (void)
  177. {
  178. return sizeof (struct panel_data);
  179. }
  180. static void
  181. get_border_size (struct panel_data *data, int *dx1, int *dy1,
  182. int *dx2, int *dy2)
  183. {
  184. int i;
  185. *dx1 = *dy1 = *dx2 = *dy2 = 0;
  186. for (i = INDEX_SELECTED; i >= 0; i -= INDEX_SELECTED)
  187. {
  188. if (data->bitmaps[INDEX_LEFT + i])
  189. *dx1 = data->bitmaps[INDEX_LEFT + i]->width;
  190. if (data->bitmaps[INDEX_TOP + i])
  191. *dy1 = data->bitmaps[INDEX_TOP + i]->height;
  192. if (data->bitmaps[INDEX_RIGHT + i])
  193. *dx2 = (data->bitmaps[INDEX_RIGHT + i])->width;
  194. if (data->bitmaps[INDEX_BOTTOM + i])
  195. *dy2 = data->bitmaps[INDEX_BOTTOM + i]->height;
  196. }
  197. }
  198. static void
  199. panel_init_size (grub_widget_t widget)
  200. {
  201. struct panel_data *data = widget->data;
  202. int border_size, size;
  203. char *p;
  204. int i;
  205. int dx1, dy1, dx2, dy2;
  206. for (i = INDEX_TOP_LEFT; i <= INDEX_BOTTOM_RIGHT; i++)
  207. data->bitmaps[i] = get_bitmap (widget, border_names[i - INDEX_TOP_LEFT],
  208. 0, &data->bitmaps[i + INDEX_SELECTED]);
  209. data->bitmaps[INDEX_BACKGROUND] =
  210. get_bitmap (widget, "background", 0,
  211. &data->bitmaps[INDEX_BACKGROUND + INDEX_SELECTED]);
  212. p = grub_widget_get_prop (widget->node, "border_color");
  213. data->fill = data->fill_selected = 0;
  214. if (p)
  215. data->color = grub_menu_parse_color (p, &data->fill,
  216. &data->color_selected,
  217. &data->fill_selected);
  218. widget->node->flags |= GRUB_WIDGET_FLAG_DYNAMIC;
  219. if ((data->fill == data->fill_selected) &&
  220. (data->color == data->color_selected))
  221. {
  222. for (i = INDEX_TOP_LEFT + INDEX_SELECTED;
  223. i <= INDEX_BACKGROUND + INDEX_SELECTED; i++)
  224. if (data->bitmaps[i])
  225. break;
  226. if (i > INDEX_BACKGROUND + INDEX_SELECTED)
  227. widget->node->flags &= ~GRUB_WIDGET_FLAG_DYNAMIC;
  228. }
  229. p = grub_widget_get_prop (widget->node, "border_size");
  230. border_size = (p) ? grub_menu_parse_size (p, 0, 1) : 0;
  231. p = grub_widget_get_prop (widget->node, "border_left");
  232. size = (p) ? grub_menu_parse_size (p, 0, 1) : border_size;
  233. if (size > 0)
  234. {
  235. data->bitmaps[INDEX_BORDER_LEFT] = (grub_menu_region_common_t)
  236. grub_menu_region_create_rect (size, 0, 0, 0);
  237. }
  238. p = grub_widget_get_prop (widget->node, "border_right");
  239. size = (p) ? grub_menu_parse_size (p, 0, 1) : border_size;
  240. if (size > 0)
  241. {
  242. data->bitmaps[INDEX_BORDER_RIGHT] = (grub_menu_region_common_t)
  243. grub_menu_region_create_rect (size, 0, 0, 0);
  244. }
  245. p = grub_widget_get_prop (widget->node, "border_top");
  246. size = (p) ? grub_menu_parse_size (p, 0, 0) : border_size;
  247. if (size > 0)
  248. {
  249. data->bitmaps[INDEX_BORDER_TOP] = (grub_menu_region_common_t)
  250. grub_menu_region_create_rect (0, size, 0, 0);
  251. }
  252. p = grub_widget_get_prop (widget->node, "border_bottom");
  253. size = (p) ? grub_menu_parse_size (p, 0, 0) : border_size;
  254. if (size > 0)
  255. {
  256. data->bitmaps[INDEX_BORDER_BOTTOM] = (grub_menu_region_common_t)
  257. grub_menu_region_create_rect (0, size, 0, 0);
  258. }
  259. widget->node->flags |= GRUB_WIDGET_FLAG_TRANSPARENT;
  260. get_border_size (data, &dx1, &dy1, &dx2, &dy2);
  261. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_WIDTH))
  262. {
  263. widget->width += dx1 + dx2;
  264. if (data->bitmaps[INDEX_BORDER_LEFT])
  265. widget->width += data->bitmaps[INDEX_BORDER_LEFT]->width;
  266. if (data->bitmaps[INDEX_BORDER_RIGHT])
  267. widget->width += data->bitmaps[INDEX_BORDER_RIGHT]->width;
  268. adjust_margin (widget, "padding", MARGIN_WIDTH);
  269. adjust_margin (widget, "margin", MARGIN_WIDTH);
  270. }
  271. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_HEIGHT))
  272. {
  273. widget->height += dy1 + dy2;
  274. if (data->bitmaps[INDEX_BORDER_TOP])
  275. widget->height += data->bitmaps[INDEX_BORDER_TOP]->height;
  276. if (data->bitmaps[INDEX_BORDER_BOTTOM])
  277. widget->height += data->bitmaps[INDEX_BORDER_BOTTOM]->height;
  278. adjust_margin (widget, "padding", MARGIN_HEIGHT);
  279. adjust_margin (widget, "margin", MARGIN_HEIGHT);
  280. }
  281. }
  282. static void
  283. resize_border (grub_widget_t widget, grub_menu_region_common_t *bitmaps,
  284. int index, int x, int y, int width, int height)
  285. {
  286. if (bitmaps[index])
  287. {
  288. grub_menu_region_scale (bitmaps[index], width, height);
  289. bitmaps[index]->ofs_x = x + widget->inner_x;
  290. bitmaps[index]->ofs_y = y + widget->inner_y;
  291. }
  292. if (bitmaps[index + INDEX_SELECTED])
  293. {
  294. grub_menu_region_scale (bitmaps[index + INDEX_SELECTED],
  295. width, height);
  296. bitmaps[index + INDEX_SELECTED]->ofs_x = x + widget->inner_x;
  297. bitmaps[index + INDEX_SELECTED]->ofs_y = y + widget->inner_y;
  298. }
  299. }
  300. static void
  301. panel_fini_size (grub_widget_t widget)
  302. {
  303. struct panel_data *data = widget->data;
  304. int dx1, dy1, dx2, dy2, bw1, bh1, bw2, bh2, width, height;
  305. adjust_margin (widget, "padding", MARGIN_FINI);
  306. get_border_size (data, &dx1, &dy1, &dx2, &dy2);
  307. bw1 = (data->bitmaps[INDEX_BORDER_LEFT]) ?
  308. data->bitmaps[INDEX_BORDER_LEFT]->width : 0;
  309. bw2 = (data->bitmaps[INDEX_BORDER_RIGHT]) ?
  310. data->bitmaps[INDEX_BORDER_RIGHT]->width : 0;
  311. bh1 = (data->bitmaps[INDEX_BORDER_TOP]) ?
  312. data->bitmaps[INDEX_BORDER_TOP]->height : 0;
  313. bh2 = (data->bitmaps[INDEX_BORDER_BOTTOM]) ?
  314. data->bitmaps[INDEX_BORDER_BOTTOM]->height : 0;
  315. width = widget->inner_width - dx1 - dx2 - bw1 - bw2;
  316. height = widget->inner_height - dy1 - dy2 - bh1 - bh2;
  317. resize_border (widget, data->bitmaps, INDEX_TOP_LEFT,
  318. bw1, bh1, dx1, dy1);
  319. resize_border (widget, data->bitmaps, INDEX_TOP,
  320. bw1 + dx1, bh1, width, dy1);
  321. resize_border (widget, data->bitmaps, INDEX_TOP_RIGHT,
  322. bw1 + dx1 + width, bh1, dx2, dy1);
  323. resize_border (widget, data->bitmaps, INDEX_LEFT,
  324. bw1, bh1 + dy1, dx1, height);
  325. resize_border (widget, data->bitmaps, INDEX_RIGHT,
  326. bw1 + dx1 + width, bh1 + dy1, dx2, height);
  327. resize_border (widget, data->bitmaps, INDEX_BOTTOM_LEFT,
  328. bw1, bh1 + dy1 + height, dx1, dy2);
  329. resize_border (widget, data->bitmaps, INDEX_BOTTOM,
  330. bw1 + dx1, bh1 + dy1 + height, width, dy2);
  331. resize_border (widget, data->bitmaps, INDEX_BOTTOM_RIGHT,
  332. bw1 + dx1 + width, bh1 + dy1 + height, dx2, dy2);
  333. resize_border (widget, data->bitmaps, INDEX_BACKGROUND,
  334. bw1 + dx1, bh1 + dy1, width, height);
  335. if (data->bitmaps[INDEX_BORDER_TOP])
  336. {
  337. data->bitmaps[INDEX_BORDER_TOP]->ofs_x = widget->inner_x;
  338. data->bitmaps[INDEX_BORDER_TOP]->ofs_y = widget->inner_y;
  339. data->bitmaps[INDEX_BORDER_TOP]->width = widget->inner_width;
  340. }
  341. if (data->bitmaps[INDEX_BORDER_BOTTOM])
  342. {
  343. data->bitmaps[INDEX_BORDER_BOTTOM]->ofs_x = widget->inner_x;
  344. data->bitmaps[INDEX_BORDER_BOTTOM]->ofs_y = widget->inner_y +
  345. widget->inner_height - bh2;
  346. data->bitmaps[INDEX_BORDER_BOTTOM]->width = widget->inner_width;
  347. }
  348. if (data->bitmaps[INDEX_BORDER_LEFT])
  349. {
  350. data->bitmaps[INDEX_BORDER_LEFT]->ofs_x = widget->inner_x;
  351. data->bitmaps[INDEX_BORDER_LEFT]->ofs_y = widget->inner_y + bh1;
  352. data->bitmaps[INDEX_BORDER_LEFT]->height =
  353. widget->inner_height - bh1 - bh2;
  354. }
  355. if (data->bitmaps[INDEX_BORDER_RIGHT])
  356. {
  357. data->bitmaps[INDEX_BORDER_RIGHT]->ofs_x = widget->inner_x +
  358. widget->inner_width - bw2;
  359. data->bitmaps[INDEX_BORDER_RIGHT]->ofs_y = widget->inner_y + bh1;
  360. data->bitmaps[INDEX_BORDER_RIGHT]->height =
  361. widget->inner_height - bh1 - bh2;
  362. }
  363. widget->inner_width = width;
  364. widget->inner_height = height;
  365. widget->inner_x += bw1 + dx1;
  366. widget->inner_y += bh1 + dy1;
  367. adjust_margin (widget, "margin", MARGIN_FINI);
  368. }
  369. static void
  370. panel_free (grub_widget_t widget)
  371. {
  372. struct panel_data *data = widget->data;
  373. int i;
  374. for (i = 0; i < INDEX_COUNT; i++)
  375. grub_menu_region_free (data->bitmaps[i]);
  376. }
  377. static void
  378. panel_draw (grub_widget_t widget, grub_menu_region_update_list_t *head,
  379. int x, int y, int width, int height)
  380. {
  381. struct panel_data *data = widget->data;
  382. int i, ofs;
  383. for (i = INDEX_BORDER_TOP; i <= INDEX_BORDER_BOTTOM; i++)
  384. if (data->bitmaps[i])
  385. {
  386. if (widget->node->flags & GRUB_WIDGET_FLAG_SELECTED)
  387. {
  388. ((grub_menu_region_rect_t) data->bitmaps[i])->color =
  389. data->color_selected;
  390. ((grub_menu_region_rect_t) data->bitmaps[i])->fill =
  391. data->fill_selected;
  392. }
  393. else
  394. {
  395. ((grub_menu_region_rect_t) data->bitmaps[i])->color =
  396. data->color;
  397. ((grub_menu_region_rect_t) data->bitmaps[i])->fill =
  398. data->fill;
  399. }
  400. grub_menu_region_add_update (head, data->bitmaps[i],
  401. widget->org_x, widget->org_y,
  402. x, y, width, height);
  403. }
  404. ofs = (widget->node->flags & GRUB_WIDGET_FLAG_SELECTED) ? INDEX_SELECTED : 0;
  405. for (i = INDEX_TOP_LEFT; i <= INDEX_BACKGROUND; i++)
  406. if (data->bitmaps[i + ofs])
  407. grub_menu_region_add_update (head, data->bitmaps[i + ofs],
  408. widget->org_x, widget->org_y,
  409. x, y, width, height);
  410. else
  411. grub_menu_region_add_update (head, data->bitmaps[i],
  412. widget->org_x, widget->org_y,
  413. x, y, width, height);
  414. }
  415. static struct grub_widget_class panel_widget_class =
  416. {
  417. .name = "panel",
  418. .get_data_size = panel_get_data_size,
  419. .init_size = panel_init_size,
  420. .fini_size = panel_fini_size,
  421. .free = panel_free,
  422. .draw = panel_draw
  423. };
  424. struct image_data
  425. {
  426. grub_menu_region_common_t image;
  427. grub_menu_region_common_t image_selected;
  428. };
  429. static int
  430. image_get_data_size (void)
  431. {
  432. return sizeof (struct image_data);
  433. }
  434. static void
  435. image_init_size (grub_widget_t widget)
  436. {
  437. struct image_data *data = widget->data;
  438. data->image = get_bitmap (widget, "image", 0, &data->image_selected);
  439. if (! data->image)
  440. return;
  441. if (data->image_selected)
  442. widget->node->flags |= GRUB_WIDGET_FLAG_DYNAMIC;
  443. else
  444. widget->node->flags &= ~GRUB_WIDGET_FLAG_DYNAMIC;
  445. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_WIDTH))
  446. widget->width = data->image->width;
  447. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_HEIGHT))
  448. widget->height = data->image->height;
  449. }
  450. static void
  451. image_fini_size (grub_widget_t widget)
  452. {
  453. struct image_data *data = widget->data;
  454. grub_menu_region_scale (data->image, widget->width, widget->height);
  455. grub_menu_region_scale (data->image_selected, widget->width, widget->height);
  456. }
  457. static void
  458. image_free (grub_widget_t widget)
  459. {
  460. struct image_data *data = widget->data;
  461. grub_menu_region_free (data->image);
  462. grub_menu_region_free (data->image_selected);
  463. }
  464. static void
  465. image_draw (grub_widget_t widget, grub_menu_region_update_list_t *head,
  466. int x, int y, int width, int height)
  467. {
  468. struct image_data *data = widget->data;
  469. grub_menu_region_common_t image;
  470. image = ((widget->node->flags & GRUB_WIDGET_FLAG_SELECTED)
  471. && data->image_selected) ? data->image_selected : data->image;
  472. grub_menu_region_add_update (head, image, widget->org_x, widget->org_y,
  473. x, y, width, height);
  474. }
  475. static struct grub_widget_class image_widget_class =
  476. {
  477. .name = "image",
  478. .get_data_size = image_get_data_size,
  479. .init_size = image_init_size,
  480. .fini_size = image_fini_size,
  481. .free = image_free,
  482. .draw = image_draw
  483. };
  484. struct text_data
  485. {
  486. grub_menu_region_text_t text;
  487. grub_video_color_t color;
  488. grub_video_color_t color_selected;
  489. };
  490. static int
  491. text_get_data_size (void)
  492. {
  493. return sizeof (struct text_data);
  494. }
  495. static void
  496. text_init_size (grub_widget_t widget)
  497. {
  498. struct text_data *data = widget->data;
  499. grub_font_t font;
  500. char *p;
  501. widget->node->flags |= GRUB_WIDGET_FLAG_TRANSPARENT;
  502. p = grub_widget_get_prop (widget->node, "font");
  503. font = grub_menu_region_get_font (p);
  504. p = grub_widget_get_prop (widget->node, "color");
  505. if (p)
  506. data->color = grub_menu_parse_color (p, 0, &data->color_selected, 0);
  507. if (data->color != data->color_selected)
  508. widget->node->flags |= GRUB_WIDGET_FLAG_DYNAMIC;
  509. else
  510. widget->node->flags &= ~GRUB_WIDGET_FLAG_DYNAMIC;
  511. p = (grub_menu_region_gfx_mode ()) ?
  512. grub_widget_get_prop (widget->node, "gfx_text") : 0;
  513. if (! p)
  514. p = grub_widget_get_prop (widget->node, "text");
  515. if (p)
  516. data->text = grub_menu_region_create_text (font, 0, p);
  517. if (! data->text)
  518. return;
  519. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_WIDTH))
  520. widget->width = data->text->common.width;
  521. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_HEIGHT))
  522. widget->height = data->text->common.height;
  523. }
  524. static void
  525. text_free (grub_widget_t widget)
  526. {
  527. struct text_data *data = widget->data;
  528. grub_menu_region_free ((grub_menu_region_common_t) data->text);
  529. }
  530. static void
  531. text_draw (grub_widget_t widget, grub_menu_region_update_list_t *head,
  532. int x, int y, int width, int height)
  533. {
  534. struct text_data *data = widget->data;
  535. data->text->color = ((widget->node->flags & GRUB_WIDGET_FLAG_SELECTED) ?
  536. data->color_selected : data->color);
  537. if (! (widget->node->flags & GRUB_WIDGET_FLAG_SELECTED))
  538. grub_menu_region_hide_cursor ();
  539. grub_menu_region_add_update (head, (grub_menu_region_common_t) data->text,
  540. widget->org_x, widget->org_y,
  541. x, y, width, height);
  542. }
  543. static struct grub_widget_class text_widget_class =
  544. {
  545. .name = "text",
  546. .get_data_size = text_get_data_size,
  547. .init_size = text_init_size,
  548. .free = text_free,
  549. .draw = text_draw
  550. };
  551. static grub_menu_region_text_t
  552. resize_text (grub_menu_region_text_t text, int len)
  553. {
  554. int size;
  555. size = (sizeof (struct grub_menu_region_text) + len + 1 + 15) & ~15;
  556. return grub_realloc (text, size);
  557. }
  558. #define STR_INC_STEP 8
  559. #define DEFAULT_COLUMNS 20
  560. struct password_data
  561. {
  562. grub_menu_region_text_t text;
  563. grub_video_color_t color;
  564. grub_video_color_t color_selected;
  565. char *password;
  566. int x;
  567. int pos;
  568. int char_width;
  569. int char_height;
  570. int modified;
  571. };
  572. static int
  573. password_get_data_size (void)
  574. {
  575. return sizeof (struct password_data);
  576. }
  577. static void
  578. password_init_size (grub_widget_t widget)
  579. {
  580. struct password_data *data = widget->data;
  581. grub_font_t font;
  582. char *p;
  583. widget->node->flags |= GRUB_WIDGET_FLAG_TRANSPARENT | GRUB_WIDGET_FLAG_NODE;
  584. p = grub_widget_get_prop (widget->node, "font");
  585. font = grub_menu_region_get_font (p);
  586. p = grub_widget_get_prop (widget->node, "color");
  587. if (p)
  588. data->color = grub_menu_parse_color (p, 0, &data->color_selected, 0);
  589. if (data->color != data->color_selected)
  590. widget->node->flags |= GRUB_WIDGET_FLAG_DYNAMIC;
  591. else
  592. widget->node->flags &= ~GRUB_WIDGET_FLAG_DYNAMIC;
  593. data->char_width = grub_menu_region_get_text_width (font, "*", 0, 0);
  594. data->char_height = grub_menu_region_get_text_height (font);
  595. data->text = grub_menu_region_create_text (font, 0, 0);
  596. if (! data->text)
  597. return;
  598. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_WIDTH))
  599. {
  600. int columns;
  601. p = grub_widget_get_prop (widget->node, "columns");
  602. columns = (p) ? grub_strtoul (p, 0, 0) : DEFAULT_COLUMNS;
  603. widget->width = columns * data->char_width;
  604. }
  605. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_HEIGHT))
  606. widget->height = data->char_height;
  607. }
  608. static void
  609. password_free (grub_widget_t widget)
  610. {
  611. struct password_data *data = widget->data;
  612. grub_menu_region_free ((grub_menu_region_common_t) data->text);
  613. grub_free (data->password);
  614. }
  615. static void
  616. password_draw (grub_widget_t widget, grub_menu_region_update_list_t *head,
  617. int x, int y, int width, int height)
  618. {
  619. struct password_data *data = widget->data;
  620. data->text->color = ((widget->node->flags & GRUB_WIDGET_FLAG_SELECTED) ?
  621. data->color_selected : data->color);
  622. grub_menu_region_add_update (head, (grub_menu_region_common_t) data->text,
  623. widget->org_x, widget->org_y,
  624. x, y, width, height);
  625. }
  626. static int
  627. password_scroll_x (struct password_data *data, int width)
  628. {
  629. int text_width;
  630. text_width = data->text->common.width;
  631. data->x = data->text->common.ofs_x + text_width;
  632. if ((data->x >= 0) && (data->x + data->char_width <= width))
  633. return 0;
  634. width = (width + 1) >> 1;
  635. if (width > text_width)
  636. width = text_width;
  637. data->x = width;
  638. data->text->common.ofs_x = width - text_width;
  639. return 1;
  640. }
  641. static void
  642. password_draw_cursor (grub_widget_t widget)
  643. {
  644. struct password_data *data = widget->data;
  645. grub_menu_region_draw_cursor (data->text, data->char_width, data->char_height,
  646. widget->org_x + data->x, widget->org_y);
  647. }
  648. static int
  649. password_onkey (grub_widget_t widget, int key)
  650. {
  651. struct password_data *data = widget->data;
  652. if ((key == GRUB_TERM_UP) || (key == GRUB_TERM_DOWN) ||
  653. (key == GRUB_TERM_LEFT) || (key == GRUB_TERM_RIGHT))
  654. return GRUB_WIDGET_RESULT_DONE;
  655. else if (key == GRUB_TERM_TAB)
  656. {
  657. if (data->modified)
  658. {
  659. char *buf;
  660. buf = grub_malloc (data->pos + 1);
  661. if (! buf)
  662. return grub_errno;
  663. grub_memcpy (buf, data->password, data->pos);
  664. buf[data->pos] = 0;
  665. if (grub_uitree_set_prop (widget->node, "text", buf))
  666. return grub_errno;
  667. grub_free (buf);
  668. }
  669. return GRUB_WIDGET_RESULT_SKIP;
  670. }
  671. else if ((key >= 32) && (key < 127))
  672. {
  673. if ((data->pos & (STR_INC_STEP - 1)) == 0)
  674. {
  675. data->password = grub_realloc (data->password,
  676. data->pos + STR_INC_STEP);
  677. if (! data->password)
  678. return grub_errno;
  679. }
  680. data->password[data->pos] = key;
  681. data->text = resize_text (data->text, data->pos + 1);
  682. if (! data->text)
  683. return grub_errno;
  684. data->text->text[data->pos++] = '*';
  685. data->text->text[data->pos] = 0;
  686. data->text->common.width += data->char_width;
  687. password_scroll_x (data, widget->width);
  688. grub_widget_draw (widget->node);
  689. data->modified = 1;
  690. return GRUB_WIDGET_RESULT_DONE;
  691. }
  692. else if (key == GRUB_TERM_BACKSPACE)
  693. {
  694. if (data->pos)
  695. {
  696. data->pos--;
  697. data->text->text[data->pos] = 0;
  698. data->text->common.width -= data->char_width;
  699. password_scroll_x (data, widget->width);
  700. grub_widget_draw (widget->node);
  701. data->modified = 1;
  702. }
  703. return GRUB_WIDGET_RESULT_DONE;
  704. }
  705. else
  706. return GRUB_WIDGET_RESULT_SKIP;
  707. }
  708. static struct grub_widget_class password_widget_class =
  709. {
  710. .name = "password",
  711. .get_data_size = password_get_data_size,
  712. .init_size = password_init_size,
  713. .free = password_free,
  714. .draw = password_draw,
  715. .draw_cursor = password_draw_cursor,
  716. .onkey = password_onkey,
  717. };
  718. struct progressbar_data
  719. {
  720. grub_menu_region_common_t bar;
  721. grub_menu_region_common_t bg_bar;
  722. int last_ofs;
  723. int cur_ofs;
  724. };
  725. static int
  726. progressbar_get_data_size (void)
  727. {
  728. return sizeof (struct progressbar_data);
  729. }
  730. static void
  731. progressbar_init_size (grub_widget_t widget)
  732. {
  733. struct progressbar_data *data = widget->data;
  734. grub_menu_region_common_t bar;
  735. data->bar = get_bitmap (widget, "image", 0, &data->bg_bar);
  736. bar = (data->bar) ? data->bar : data->bg_bar;
  737. if (bar)
  738. {
  739. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_WIDTH))
  740. widget->width = bar->width;
  741. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_HEIGHT))
  742. widget->height = bar->height;
  743. }
  744. else
  745. {
  746. grub_video_color_t color;
  747. grub_uint32_t fill;
  748. grub_video_color_t bg_color;
  749. grub_video_color_t bg_fill;
  750. char *p;
  751. p = grub_widget_get_prop (widget->node, "color");
  752. if (! p)
  753. p = "";
  754. fill = bg_fill = 0;
  755. color = grub_menu_parse_color (p, &fill, &bg_color, &bg_fill);
  756. data->bar = (grub_menu_region_common_t)
  757. grub_menu_region_create_rect (0, 0, color, fill);
  758. if (color != bg_color)
  759. data->bg_bar = (grub_menu_region_common_t)
  760. grub_menu_region_create_rect (0, 0, bg_color, bg_fill);
  761. }
  762. }
  763. static void
  764. progressbar_fini_size (grub_widget_t widget)
  765. {
  766. struct progressbar_data *data = widget->data;
  767. grub_menu_region_scale (data->bar, widget->width, widget->height);
  768. grub_menu_region_scale (data->bg_bar, widget->width, widget->height);
  769. }
  770. static void
  771. progressbar_free (grub_widget_t widget)
  772. {
  773. struct progressbar_data *data = widget->data;
  774. grub_menu_region_free (data->bar);
  775. grub_menu_region_free (data->bg_bar);
  776. }
  777. static void
  778. progressbar_draw (grub_widget_t widget, grub_menu_region_update_list_t *head,
  779. int x, int y, int width, int height)
  780. {
  781. struct progressbar_data *data = widget->data;
  782. int x1, y1, w1, h1;
  783. x1 = data->last_ofs;
  784. y1 = 0;
  785. w1 = data->cur_ofs - data->last_ofs;
  786. h1 = widget->height;
  787. if (grub_menu_region_check_rect (&x1, &y1, &w1, &h1, x, y, width, height))
  788. grub_menu_region_add_update (head, data->bar, widget->org_x, widget->org_y,
  789. x1, y1, w1, h1);
  790. if ((! data->last_ofs) && (data->bg_bar))
  791. {
  792. x1 = data->cur_ofs;
  793. y1 = 0;
  794. w1 = widget->width - x1;
  795. h1 = widget->height;
  796. if (grub_menu_region_check_rect (&x1, &y1, &w1, &h1,
  797. x, y, width, height))
  798. grub_menu_region_add_update (head, data->bg_bar,
  799. widget->org_x, widget->org_y,
  800. x1, y1, w1, h1);
  801. }
  802. data->last_ofs = data->cur_ofs;
  803. }
  804. static void
  805. progressbar_set_timeout (grub_widget_t widget, int total, int left)
  806. {
  807. struct progressbar_data *data = widget->data;
  808. if (left > 0)
  809. data->cur_ofs = (total - left) * widget->width / total;
  810. }
  811. static struct grub_widget_class progressbar_widget_class =
  812. {
  813. .name = "progressbar",
  814. .get_data_size = progressbar_get_data_size,
  815. .init_size = progressbar_init_size,
  816. .fini_size = progressbar_fini_size,
  817. .free = progressbar_free,
  818. .draw = progressbar_draw,
  819. .set_timeout = progressbar_set_timeout
  820. };
  821. struct circular_progress_data
  822. {
  823. grub_menu_region_common_t back;
  824. grub_menu_region_common_t tick;
  825. grub_menu_region_common_t merge;
  826. int num_ticks;
  827. int start_angle;
  828. int ticks;
  829. int update;
  830. int dir;
  831. };
  832. static int
  833. circular_progress_get_data_size (void)
  834. {
  835. return sizeof (struct circular_progress_data);
  836. }
  837. #define DEF_TICKS 24
  838. #define MAX_TICKS 100
  839. static void
  840. circular_progress_init_size (grub_widget_t widget)
  841. {
  842. struct circular_progress_data *data = widget->data;
  843. char *p;
  844. data->tick = get_bitmap (widget, "tick", 0, 0);
  845. if (! data->tick)
  846. return;
  847. data->back = get_bitmap (widget, "background", 0, 0);
  848. p = grub_widget_get_prop (widget->node, "num_ticks");
  849. data->num_ticks = (p) ? grub_strtoul (p, 0, 0) : 0;
  850. if ((data->num_ticks <= 0) || (data->num_ticks > MAX_TICKS))
  851. data->num_ticks = DEF_TICKS;
  852. p = grub_widget_get_prop (widget->node, "start_angle");
  853. data->start_angle = ((p) ? grub_strtol (p, 0, 0) : 0) *
  854. GRUB_TRIG_ANGLE_MAX / 360;
  855. p = grub_widget_get_prop (widget->node, "clockwise");
  856. data->dir = (p) ? -1 : 1;
  857. if (data->back)
  858. {
  859. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_WIDTH))
  860. widget->width = data->back->width;
  861. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_HEIGHT))
  862. widget->height = data->back->height;
  863. }
  864. data->ticks = -1;
  865. }
  866. static void
  867. circular_progress_fini_size (grub_widget_t widget)
  868. {
  869. struct circular_progress_data *data = widget->data;
  870. grub_menu_region_scale (data->back, widget->width, widget->height);
  871. }
  872. static void
  873. circular_progress_free (grub_widget_t widget)
  874. {
  875. struct circular_progress_data *data = widget->data;
  876. grub_menu_region_free (data->back);
  877. grub_menu_region_free (data->tick);
  878. }
  879. static void
  880. circular_progress_draw (grub_widget_t widget,
  881. grub_menu_region_update_list_t *head,
  882. int x, int y, int width, int height)
  883. {
  884. struct circular_progress_data *data = widget->data;
  885. if (data->update)
  886. {
  887. if (data->update < 0)
  888. grub_menu_region_add_update (head, data->back, widget->org_x,
  889. widget->org_y, x, y, width, height);
  890. grub_menu_region_add_update (head, data->tick, widget->org_x,
  891. widget->org_y, x, y, width, height);
  892. data->update = 0;
  893. }
  894. }
  895. static void
  896. circular_progress_set_timeout (grub_widget_t widget, int total, int left)
  897. {
  898. struct circular_progress_data *data = widget->data;
  899. if (! data->tick)
  900. return;
  901. if (left > 0)
  902. {
  903. int ticks = ((total - left) * data->num_ticks) / total;
  904. if (ticks > data->ticks)
  905. {
  906. int x, y, r, a;
  907. x = (widget->width - data->tick->width) / 2;
  908. y = (widget->height - data->tick->height) / 2;
  909. r = (x > y) ? y : x;
  910. a = data->start_angle +
  911. (data->dir * ticks * GRUB_TRIG_ANGLE_MAX) / data->num_ticks;
  912. x += (grub_cos (a) * r / GRUB_TRIG_FRACTION_SCALE);
  913. y -= (grub_sin (a) * r / GRUB_TRIG_FRACTION_SCALE);
  914. data->tick->ofs_x = x;
  915. data->tick->ofs_y = y;
  916. if (data->ticks >= 0)
  917. data->update = 1;
  918. else
  919. data->update = -1;
  920. data->ticks = ticks;
  921. }
  922. }
  923. }
  924. static struct grub_widget_class circular_progress_widget_class =
  925. {
  926. .name = "circular_progress",
  927. .get_data_size = circular_progress_get_data_size,
  928. .init_size = circular_progress_init_size,
  929. .fini_size = circular_progress_fini_size,
  930. .free = circular_progress_free,
  931. .draw = circular_progress_draw,
  932. .set_timeout = circular_progress_set_timeout
  933. };
  934. struct edit_data
  935. {
  936. grub_menu_region_text_t *lines;
  937. int num_lines;
  938. int max_lines;
  939. int line;
  940. int pos;
  941. int x;
  942. int y;
  943. grub_video_color_t color;
  944. grub_video_color_t color_selected;
  945. int font_height;
  946. int font_width;
  947. int modified;
  948. };
  949. #define REFERENCE_STRING "m"
  950. #define DEFAULT_MAX_LINES 100
  951. #define DEFAULT_LINES 1
  952. #define LINE_INC_STEP 8
  953. static int
  954. edit_get_data_size (void)
  955. {
  956. return sizeof (struct edit_data);
  957. }
  958. static void
  959. edit_init_size (grub_widget_t widget)
  960. {
  961. struct edit_data *data = widget->data;
  962. grub_font_t font;
  963. int num, max;
  964. char *p;
  965. widget->node->flags |= GRUB_WIDGET_FLAG_TRANSPARENT | GRUB_WIDGET_FLAG_NODE;
  966. p = grub_widget_get_prop (widget->node, "font");
  967. font = grub_menu_region_get_font (p);
  968. p = grub_widget_get_prop (widget->node, "color");
  969. if (p)
  970. data->color = grub_menu_parse_color (p, 0, &data->color_selected, 0);
  971. if (data->color != data->color_selected)
  972. widget->node->flags |= GRUB_WIDGET_FLAG_DYNAMIC;
  973. else
  974. widget->node->flags &= ~GRUB_WIDGET_FLAG_DYNAMIC;
  975. p = grub_widget_get_prop (widget->node, "max_lines");
  976. data->max_lines = (p) ? grub_strtoul (p, 0, 0) : DEFAULT_MAX_LINES;
  977. data->font_width = grub_menu_region_get_text_width (font, REFERENCE_STRING,
  978. 0, 0);
  979. data->font_height = grub_menu_region_get_text_height (font);
  980. p = grub_widget_get_prop (widget->node, "text");
  981. if (! p)
  982. p = "";
  983. num = max = 0;
  984. do
  985. {
  986. char *n;
  987. n = grub_menu_next_field (p, '\n');
  988. if (num >= max)
  989. {
  990. data->lines = grub_realloc (data->lines, (max + LINE_INC_STEP)
  991. * sizeof (data->lines[0]));
  992. if (! data->lines)
  993. return;
  994. grub_memset (data->lines + max, 0,
  995. LINE_INC_STEP * sizeof (data->lines[0]));
  996. max += LINE_INC_STEP;
  997. }
  998. data->lines[num] = grub_menu_region_create_text (font, 0, p);
  999. if (! data->lines[num])
  1000. return;
  1001. data->lines[num]->common.ofs_y = num * data->font_height;
  1002. grub_menu_restore_field (n, '\n');
  1003. num++;
  1004. p = n;
  1005. } while ((p) && (num != data->max_lines));
  1006. data->num_lines = num;
  1007. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_WIDTH))
  1008. {
  1009. int columns;
  1010. p = grub_widget_get_prop (widget->node, "columns");
  1011. columns = (p) ? grub_strtoul (p, 0, 0) : DEFAULT_COLUMNS;
  1012. widget->width = columns * data->font_width;
  1013. }
  1014. if (! (widget->node->flags & GRUB_WIDGET_FLAG_FIXED_HEIGHT))
  1015. {
  1016. int lines;
  1017. p = grub_widget_get_prop (widget->node, "lines");
  1018. lines = (p) ? grub_strtoul (p, 0, 0) : DEFAULT_LINES;
  1019. widget->height = lines * data->font_height;
  1020. }
  1021. }
  1022. static void
  1023. edit_free (grub_widget_t widget)
  1024. {
  1025. struct edit_data *data = widget->data;
  1026. int i;
  1027. for (i = 0; i < data->num_lines; i++)
  1028. grub_menu_region_free ((grub_menu_region_common_t) data->lines[i]);
  1029. grub_free (data->lines);
  1030. }
  1031. static void
  1032. edit_draw (grub_widget_t widget, grub_menu_region_update_list_t *head,
  1033. int x, int y, int width, int height)
  1034. {
  1035. struct edit_data *data = widget->data;
  1036. grub_video_color_t color;
  1037. grub_menu_region_text_t *p;
  1038. int i;
  1039. color = ((widget->node->flags & GRUB_WIDGET_FLAG_SELECTED) ?
  1040. data->color_selected : data->color);
  1041. for (i = 0, p = data->lines; i < data->num_lines; i++, p++)
  1042. if (*p)
  1043. {
  1044. (*p)->color = color;
  1045. grub_menu_region_add_update (head,
  1046. (grub_menu_region_common_t) *p,
  1047. widget->org_x, widget->org_y,
  1048. x, y, width, height);
  1049. }
  1050. }
  1051. static int cursor_off;
  1052. static void
  1053. edit_draw_cursor (grub_widget_t widget)
  1054. {
  1055. struct edit_data *data = widget->data;
  1056. grub_font_t font;
  1057. char *line;
  1058. int cursor_width;
  1059. if (cursor_off)
  1060. return;
  1061. line = data->lines[data->line]->text;
  1062. font = data->lines[data->line]->font;
  1063. cursor_width = (line[data->pos]) ?
  1064. grub_menu_region_get_text_width (font, line + data->pos, 1, 0) :
  1065. data->font_width;
  1066. grub_menu_region_draw_cursor (data->lines[data->line], cursor_width,
  1067. data->font_height, widget->org_x + data->x,
  1068. widget->org_y + data->y);
  1069. }
  1070. static int
  1071. edit_scroll_x (struct edit_data *data, int text_width, int width)
  1072. {
  1073. data->x = data->lines[data->line]->common.ofs_x + text_width;
  1074. if ((data->x >= 0) && (data->x + data->font_width <= width))
  1075. return 0;
  1076. width = (width + 1) >> 1;
  1077. if (width > text_width)
  1078. width = text_width;
  1079. data->x = width;
  1080. data->lines[data->line]->common.ofs_x = width - text_width;
  1081. return 1;
  1082. }
  1083. static void
  1084. edit_move_y (struct edit_data *data, int delta)
  1085. {
  1086. int i;
  1087. grub_menu_region_text_t *p;
  1088. for (i = 0, p = data->lines; i < data->num_lines; i++, p++)
  1089. if (*p)
  1090. (*p)->common.ofs_y += delta;
  1091. }
  1092. static int
  1093. edit_scroll_y (struct edit_data *data, int height)
  1094. {
  1095. int text_height, delta;
  1096. text_height = data->font_height * data->line;
  1097. data->y = data->lines[0]->common.ofs_y + text_height;
  1098. if ((data->lines[0]->common.ofs_y <= 0) &&
  1099. (data->y >= 0) && (data->y + data->font_height <= height))
  1100. return 0;
  1101. height = (height + 1) >> 1;
  1102. if (height > text_height)
  1103. height = text_height;
  1104. delta = height - data->y;
  1105. data->y = height;
  1106. edit_move_y (data, delta);
  1107. return 1;
  1108. }
  1109. static int
  1110. edit_prev_char_width (grub_font_t font, char *line, int pos, int* len)
  1111. {
  1112. int width;
  1113. char *p;
  1114. width = 0;
  1115. p = line;
  1116. while (1)
  1117. {
  1118. int w, n;
  1119. w = grub_menu_region_get_text_width (font, p, 1, &n);
  1120. pos -= n;
  1121. if (pos <= 0)
  1122. break;
  1123. p += n;
  1124. width += w;
  1125. }
  1126. *len = p - line;
  1127. return width;
  1128. }
  1129. static void
  1130. draw_region (grub_uitree_t node, int x, int y, int width, int height)
  1131. {
  1132. grub_menu_region_update_list_t head;
  1133. head = 0;
  1134. grub_widget_draw_region (&head, node, x, y, width, height);
  1135. grub_menu_region_apply_update (head);
  1136. }
  1137. static int
  1138. edit_handle_key (grub_widget_t widget, int key)
  1139. {
  1140. struct edit_data *data = widget->data;
  1141. grub_font_t font;
  1142. char *line;
  1143. int update_x, update_y, update_width, update_height, text_width, scroll_y;
  1144. line = data->lines[data->line]->text;
  1145. font = data->lines[data->line]->font;
  1146. update_x = data->x;
  1147. update_y = data->y;
  1148. update_width = (line[data->pos]) ?
  1149. grub_menu_region_get_text_width (font, line + data->pos, 1, 0) :
  1150. data->font_width;
  1151. update_height = data->font_height;
  1152. text_width = -1;
  1153. scroll_y = 0;
  1154. if (key == GRUB_TERM_LEFT)
  1155. {
  1156. if (! data->pos)
  1157. return GRUB_WIDGET_RESULT_DONE;
  1158. text_width = edit_prev_char_width (font, line, data->pos, &data->pos);
  1159. }
  1160. else if (key == GRUB_TERM_RIGHT)
  1161. {
  1162. int n;
  1163. if (! line[data->pos])
  1164. return GRUB_WIDGET_RESULT_DONE;
  1165. text_width = data->x - data->lines[data->line]->common.ofs_x +
  1166. grub_menu_region_get_text_width (font, line + data->pos, 1, &n);
  1167. data->pos += n;
  1168. }
  1169. else if (key == GRUB_TERM_HOME)
  1170. {
  1171. if (! data->pos)
  1172. return GRUB_WIDGET_RESULT_DONE;
  1173. text_width = data->pos = 0;
  1174. }
  1175. else if (key == GRUB_TERM_END)
  1176. {
  1177. text_width = data->lines[data->line]->common.width;
  1178. data->pos = grub_strlen (line);
  1179. }
  1180. else if ((key == GRUB_TERM_UP) || (key == GRUB_TERM_CTRL_P) ||
  1181. (key == GRUB_TERM_PPAGE))
  1182. {
  1183. int n;
  1184. if (! data->line)
  1185. return GRUB_WIDGET_RESULT_DONE;
  1186. n = (key == GRUB_TERM_PPAGE) ? widget->height / data->font_height : 1;
  1187. if (n > data->line)
  1188. n = data->line;
  1189. if (! n)
  1190. return GRUB_WIDGET_RESULT_DONE;
  1191. if ((data->line + 1 == data->num_lines) && (! *line))
  1192. {
  1193. grub_menu_region_free ((grub_menu_region_common_t)
  1194. data->lines[data->line]);
  1195. data->lines[data->line] = 0;
  1196. data->num_lines--;
  1197. }
  1198. data->line -= n;
  1199. scroll_y = 1;
  1200. }
  1201. else if ((key == GRUB_TERM_DOWN) || (key == GRUB_TERM_CTRL_N))
  1202. {
  1203. if (data->max_lines == 1)
  1204. return GRUB_WIDGET_RESULT_DONE;
  1205. data->line++;
  1206. data->y += data->font_height;
  1207. if (data->line >= data->num_lines)
  1208. {
  1209. data->num_lines++;
  1210. if ((data->num_lines & (LINE_INC_STEP - 1)) == 0)
  1211. {
  1212. data->lines =
  1213. grub_realloc (data->lines,
  1214. (data->num_lines + LINE_INC_STEP) *
  1215. sizeof (void *));
  1216. if (! data->lines)
  1217. return grub_errno;
  1218. grub_memset (data->lines + data->num_lines, 0,
  1219. LINE_INC_STEP * sizeof (void *));
  1220. }
  1221. }
  1222. if (! data->lines[data->line])
  1223. {
  1224. data->lines[data->line] = grub_menu_region_create_text (font, 0, 0);
  1225. if (! data->lines[data->line])
  1226. return grub_errno;
  1227. data->lines[data->line]->common.ofs_y = data->y;
  1228. }
  1229. scroll_y = 1;
  1230. }
  1231. else if (key == '\r')
  1232. {
  1233. int i;
  1234. if (data->max_lines == 1)
  1235. return GRUB_WIDGET_RESULT_DONE;
  1236. data->line++;
  1237. data->num_lines++;
  1238. if ((data->num_lines & (LINE_INC_STEP - 1)) == 0)
  1239. {
  1240. data->lines = grub_realloc (data->lines,
  1241. (data->num_lines + LINE_INC_STEP) *
  1242. sizeof (void *));
  1243. if (! data->lines)
  1244. return grub_errno;
  1245. grub_memset (data->lines + data->num_lines, 0,
  1246. LINE_INC_STEP * sizeof (void *));
  1247. }
  1248. for (i = data->num_lines - 1; i > data->line; i--)
  1249. {
  1250. data->lines[i] = data->lines[i - 1];
  1251. data->lines[i]->common.ofs_y += data->font_height;
  1252. }
  1253. data->y += data->font_height;
  1254. data->lines[data->line] =
  1255. grub_menu_region_create_text (font, 0, line + data->pos);
  1256. data->lines[data->line]->common.ofs_y = data->y;
  1257. line[data->pos] = 0;
  1258. data->lines[data->line - 1]->common.width =
  1259. grub_menu_region_get_text_width (font, line, 0, 0);
  1260. data->lines[data->line - 1]->common.ofs_x = 0;
  1261. data->x = 0;
  1262. data->pos = 0;
  1263. update_x = 0;
  1264. update_width = widget->width;
  1265. update_height = (data->num_lines - data->line + 1) * data->font_height;
  1266. scroll_y = 1;
  1267. data->modified = 1;
  1268. }
  1269. else if (key == GRUB_TERM_NPAGE)
  1270. {
  1271. int n;
  1272. n = widget->height / data->font_height;
  1273. if (data->line + n >= data->num_lines)
  1274. n = data->num_lines - 1 - data->line;
  1275. if (! n)
  1276. return GRUB_WIDGET_RESULT_DONE;
  1277. data->line += n;
  1278. scroll_y = 1;
  1279. }
  1280. else if ((key >= 32) && (key < 127))
  1281. {
  1282. int len, i;
  1283. len = grub_strlen (line);
  1284. data->lines[data->line] = resize_text (data->lines[data->line], len + 1);
  1285. if (! data->lines[data->line])
  1286. return grub_errno;
  1287. line = data->lines[data->line]->text;
  1288. for (i = len - 1; i >= data->pos; i--)
  1289. line[i + 1] = line[i];
  1290. line[len + 1] = 0;
  1291. line[data->pos] = key;
  1292. data->lines[data->line]->common.width =
  1293. grub_menu_region_get_text_width (font, line, 0, 0);
  1294. text_width = data->x - data->lines[data->line]->common.ofs_x;
  1295. update_width = data->lines[data->line]->common.width - text_width;
  1296. text_width +=
  1297. grub_menu_region_get_text_width (font, line + data->pos, 1, 0);
  1298. data->pos++;
  1299. data->modified = 1;
  1300. }
  1301. else if (key == GRUB_TERM_BACKSPACE)
  1302. {
  1303. int n, delta;
  1304. char *p;
  1305. if (! data->pos)
  1306. {
  1307. int i, len;
  1308. if (! data->line)
  1309. return GRUB_WIDGET_RESULT_DONE;
  1310. data->line--;
  1311. data->pos = grub_strlen (data->lines[data->line]->text);
  1312. len = grub_strlen (line);
  1313. if (len)
  1314. {
  1315. data->lines[data->line] = resize_text (data->lines[data->line],
  1316. data->pos + len);
  1317. if (! data->lines[data->line])
  1318. return 1;
  1319. grub_strcpy (data->lines[data->line]->text + data->pos,
  1320. line);
  1321. }
  1322. grub_menu_region_free ((grub_menu_region_common_t)
  1323. data->lines[data->line + 1]);
  1324. for (i = data->line + 1; i < data->num_lines - 1; i++)
  1325. {
  1326. data->lines[i] = data->lines[i + 1];
  1327. data->lines[i]->common.ofs_y -= data->font_height;
  1328. }
  1329. data->num_lines--;
  1330. data->lines[data->num_lines] = 0;
  1331. data->x = data->lines[data->line]->common.width;
  1332. data->lines[data->line]->common.width =
  1333. grub_menu_region_get_text_width (font,
  1334. data->lines[data->line]->text,
  1335. 0, 0);
  1336. data->y -= data->font_height;
  1337. edit_scroll_x (data, data->x, widget->width);
  1338. update_x = 0;
  1339. update_width = widget->width;
  1340. update_y = data->y;
  1341. update_height = (data->num_lines - data->line + 1) *
  1342. data->font_height;
  1343. }
  1344. else
  1345. {
  1346. text_width = edit_prev_char_width (font, line, data->pos, &n);
  1347. update_width = data->lines[data->line]->common.width -
  1348. text_width;
  1349. if (! line[data->pos])
  1350. update_width += data->font_width;
  1351. delta = data->pos - n;
  1352. for (p = line + data->pos; ; p++)
  1353. {
  1354. *(p - delta) = *p;
  1355. if (! *p)
  1356. break;
  1357. }
  1358. data->pos = n;
  1359. data->lines[data->line]->common.width =
  1360. grub_menu_region_get_text_width (font, line, 0, 0);
  1361. update_x = data->lines[data->line]->common.ofs_x + text_width;
  1362. }
  1363. data->modified = 1;
  1364. }
  1365. else if ((key == GRUB_TERM_CTRL_X) || (key == GRUB_TERM_TAB))
  1366. {
  1367. if (data->modified)
  1368. {
  1369. int i, len;
  1370. char *buf, *p;
  1371. len = 0;
  1372. for (i = 0; i < data->num_lines; i++)
  1373. len += grub_strlen (data->lines[i]->text) + 1;
  1374. buf = grub_malloc (len);
  1375. if (! buf)
  1376. return grub_errno;
  1377. p = buf;
  1378. for (i = 0; i < data->num_lines; i++)
  1379. {
  1380. grub_strcpy (p, data->lines[i]->text);
  1381. p += grub_strlen (p);
  1382. *(p++) = '\n';
  1383. }
  1384. *(p - 1) = 0;
  1385. if (grub_uitree_set_prop (widget->node, "text", buf))
  1386. return grub_errno;
  1387. grub_free (buf);
  1388. data->modified = 0;
  1389. }
  1390. return (key == GRUB_TERM_TAB) ? GRUB_WIDGET_RESULT_SKIP : 0;
  1391. }
  1392. else
  1393. return GRUB_WIDGET_RESULT_SKIP;
  1394. if ((text_width >= 0) && (edit_scroll_x (data, text_width, widget->width)))
  1395. {
  1396. update_x = 0;
  1397. update_width = widget->width;
  1398. }
  1399. if (scroll_y)
  1400. {
  1401. if ((data->max_lines) && (data->line >= data->max_lines))
  1402. {
  1403. int i, n;
  1404. n = widget->height / (2 * data->font_height);
  1405. if (n < 1)
  1406. n = 1;
  1407. else if (n > data->line)
  1408. n = data->line;
  1409. for (i = 0; i < n; i++)
  1410. grub_menu_region_free ((grub_menu_region_common_t) data->lines[i]);
  1411. for (i = 0; i <= data->line - n; i++)
  1412. data->lines[i] = data->lines[i + n];
  1413. for (; i <= data->line; i++)
  1414. data->lines[i] = 0;
  1415. data->line -= n;
  1416. data->num_lines -= n;
  1417. }
  1418. data->x = 0;
  1419. data->pos = 0;
  1420. if (edit_scroll_y (data, widget->height))
  1421. {
  1422. data->x = data->lines[data->line]->common.ofs_x = 0;
  1423. update_x = 0;
  1424. update_y = 0;
  1425. update_width = widget->width;
  1426. update_height = widget->height;
  1427. }
  1428. else if (edit_scroll_x (data, 0, widget->width))
  1429. {
  1430. draw_region (widget->node, update_x, update_y,
  1431. update_width, update_height);
  1432. update_x = 0;
  1433. update_y = data->y;
  1434. update_width = widget->width;
  1435. update_height = data->font_height;
  1436. }
  1437. }
  1438. draw_region (widget->node, update_x, update_y, update_width, update_height);
  1439. return GRUB_WIDGET_RESULT_DONE;
  1440. }
  1441. static int
  1442. edit_onkey (grub_widget_t widget, int key)
  1443. {
  1444. return edit_handle_key (widget, key);
  1445. }
  1446. static struct grub_widget_class edit_widget_class =
  1447. {
  1448. .name = "edit",
  1449. .get_data_size = edit_get_data_size,
  1450. .init_size = edit_init_size,
  1451. .free = edit_free,
  1452. .draw = edit_draw,
  1453. .draw_cursor = edit_draw_cursor,
  1454. .onkey = edit_onkey,
  1455. };
  1456. static grub_widget_t cur_term;
  1457. #define GRUB_PROMPT "grub> "
  1458. struct term_data
  1459. {
  1460. struct edit_data edit;
  1461. int hist_pos;
  1462. };
  1463. static int
  1464. term_get_data_size (void)
  1465. {
  1466. return sizeof (struct term_data);
  1467. }
  1468. static void
  1469. term_free (grub_widget_t widget)
  1470. {
  1471. if (cur_term == widget)
  1472. cur_term = 0;
  1473. edit_free (widget);
  1474. }
  1475. static void
  1476. term_draw (grub_widget_t widget, grub_menu_region_update_list_t *head,
  1477. int x, int y, int width, int height)
  1478. {
  1479. if ((! (widget->node->flags & GRUB_WIDGET_FLAG_SELECTED)) &&
  1480. (cur_term == widget))
  1481. cur_term = 0;
  1482. edit_draw (widget, head, x, y, width, height);
  1483. }
  1484. static void
  1485. term_draw_cursor (grub_widget_t widget)
  1486. {
  1487. struct edit_data *data = widget->data;
  1488. cur_term = widget;
  1489. if ((data->line + 1 == data->num_lines) &&
  1490. (! data->lines[data->line]->text[0]))
  1491. grub_printf (GRUB_PROMPT);
  1492. else
  1493. {
  1494. int len;
  1495. len = sizeof (GRUB_PROMPT) - 1;
  1496. if ((! grub_strncmp (data->lines[data->line]->text, GRUB_PROMPT, len))
  1497. && (data->pos < len))
  1498. {
  1499. data->pos = len;
  1500. data->x = grub_menu_region_get_text_width (data->lines[0]->font,
  1501. GRUB_PROMPT, 0, 0);
  1502. }
  1503. }
  1504. edit_draw_cursor (widget);
  1505. }
  1506. static void
  1507. clear_rest (grub_widget_t widget)
  1508. {
  1509. struct edit_data *data = widget->data;
  1510. int i;
  1511. for (i = data->line + 1; i < data->num_lines; i++)
  1512. {
  1513. grub_menu_region_free ((grub_menu_region_common_t) data->lines[i]);
  1514. data->lines[i] = 0;
  1515. }
  1516. if (data->num_lines > data->line + 1)
  1517. {
  1518. int height;
  1519. height = (data->num_lines - data->line - 1) * data->font_height;
  1520. draw_region (widget->node, 0, data->y + data->font_height,
  1521. widget->width, height);
  1522. data->num_lines = data->line + 1;
  1523. }
  1524. }
  1525. /* A completion hook to print items. */
  1526. static void
  1527. print_completion (const char *item, grub_completion_type_t type, int count)
  1528. {
  1529. if (count == 0)
  1530. {
  1531. /* If this is the first time, print a label. */
  1532. const char *what;
  1533. clear_rest (cur_term);
  1534. switch (type)
  1535. {
  1536. case GRUB_COMPLETION_TYPE_COMMAND:
  1537. what = "commands";
  1538. break;
  1539. case GRUB_COMPLETION_TYPE_DEVICE:
  1540. what = "devices";
  1541. break;
  1542. case GRUB_COMPLETION_TYPE_FILE:
  1543. what = "files";
  1544. break;
  1545. case GRUB_COMPLETION_TYPE_PARTITION:
  1546. what = "partitions";
  1547. break;
  1548. case GRUB_COMPLETION_TYPE_ARGUMENT:
  1549. what = "arguments";
  1550. break;
  1551. default:
  1552. what = "things";
  1553. break;
  1554. }
  1555. grub_printf ("\nPossible %s are:\n", what);
  1556. }
  1557. if (type == GRUB_COMPLETION_TYPE_PARTITION)
  1558. {
  1559. grub_print_device_info (item);
  1560. grub_errno = GRUB_ERR_NONE;
  1561. }
  1562. else
  1563. {
  1564. struct edit_data *data = cur_term->data;
  1565. int width;
  1566. width = data->x + data->font_width +
  1567. grub_menu_region_get_text_width (data->lines[0]->font, item, 0, 0);
  1568. if (width >= cur_term->width)
  1569. edit_handle_key (cur_term, GRUB_TERM_DOWN);
  1570. grub_printf (" %s", item);
  1571. }
  1572. }
  1573. static int
  1574. term_onkey (grub_widget_t widget, int key)
  1575. {
  1576. struct term_data *data = widget->data;
  1577. int has_prompt;
  1578. has_prompt = (! grub_strncmp (data->edit.lines[data->edit.line]->text,
  1579. GRUB_PROMPT, sizeof (GRUB_PROMPT) - 1));
  1580. if ((key == '\r') && (has_prompt))
  1581. {
  1582. char *cmd;
  1583. clear_rest (widget);
  1584. cmd = data->edit.lines[data->edit.line]->text +
  1585. sizeof (GRUB_PROMPT) - 1;
  1586. edit_handle_key (widget, GRUB_TERM_DOWN);
  1587. if (*cmd)
  1588. {
  1589. int len;
  1590. grub_uint32_t *ustr, *last;
  1591. len = grub_utf8_to_ucs4_alloc (cmd, &ustr, &last);
  1592. if (len != -1)
  1593. {
  1594. if (! data->hist_pos)
  1595. grub_history_add (ustr, len);
  1596. else
  1597. grub_history_replace (data->hist_pos - 1, ustr, len);
  1598. data->hist_pos = 0;
  1599. grub_free (ustr);
  1600. }
  1601. grub_parser_execute (cmd);
  1602. if (grub_widget_refresh)
  1603. return GRUB_WIDGET_RESULT_DONE;
  1604. if (data->edit.pos)
  1605. edit_handle_key (widget, GRUB_TERM_DOWN);
  1606. if (grub_errno)
  1607. {
  1608. grub_print_error ();
  1609. grub_errno = 0;
  1610. }
  1611. }
  1612. return GRUB_WIDGET_RESULT_DONE;
  1613. }
  1614. else if (((key == GRUB_TERM_UP) || (key == GRUB_TERM_DOWN)) && (has_prompt))
  1615. {
  1616. int text_width;
  1617. char *line;
  1618. if (key == GRUB_TERM_UP)
  1619. {
  1620. if (data->hist_pos < grub_history_used ())
  1621. data->hist_pos++;
  1622. else
  1623. return GRUB_WIDGET_RESULT_DONE;
  1624. }
  1625. else
  1626. {
  1627. if (data->hist_pos > 0)
  1628. data->hist_pos--;
  1629. else
  1630. return GRUB_WIDGET_RESULT_DONE;
  1631. }
  1632. if (data->hist_pos > 0)
  1633. {
  1634. grub_uint32_t *ustr, *p;
  1635. int len;
  1636. ustr = grub_history_get (data->hist_pos - 1);
  1637. len = 0;
  1638. p = ustr;
  1639. while (*p)
  1640. {
  1641. p++;
  1642. len++;
  1643. }
  1644. line = grub_ucs4_to_utf8_alloc (ustr, len);
  1645. }
  1646. else
  1647. line = grub_strdup ("");
  1648. data->edit.lines[data->edit.line] =
  1649. resize_text (data->edit.lines[data->edit.line],
  1650. grub_strlen (line) + sizeof (GRUB_PROMPT) - 1);
  1651. if (! data->edit.lines[data->edit.line])
  1652. {
  1653. grub_free (line);
  1654. return grub_errno;
  1655. }
  1656. grub_strcpy (data->edit.lines[data->edit.line]->text
  1657. + sizeof (GRUB_PROMPT) - 1, line);
  1658. grub_free (line);
  1659. line = data->edit.lines[data->edit.line]->text;
  1660. data->edit.pos = grub_strlen (line);
  1661. text_width = data->edit.lines[data->edit.line]->common.width =
  1662. grub_menu_region_get_text_width (data->edit.lines[0]->font, line,
  1663. 0, 0);
  1664. data->edit.lines[data->edit.line]->common.ofs_x = 0;
  1665. edit_scroll_x (&data->edit, text_width, widget->width);
  1666. draw_region (widget->node, 0, data->edit.y, widget->width,
  1667. data->edit.font_height);
  1668. return GRUB_WIDGET_RESULT_DONE;
  1669. }
  1670. else if (key == GRUB_TERM_TAB)
  1671. {
  1672. char *insert, backup;
  1673. int restore, pos, size, len, ilen, i;
  1674. int update_x, update_y, update_width, update_height, text_width;
  1675. char *line;
  1676. update_x = data->edit.x;
  1677. update_y = data->edit.y;
  1678. pos = data->edit.pos;
  1679. line = data->edit.lines[data->edit.line]->text;
  1680. backup = line[pos];
  1681. line[pos] = 0;
  1682. insert = grub_complete (line + sizeof (GRUB_PROMPT) - 1,
  1683. &restore, print_completion);
  1684. for (i = data->edit.line; i >= 0; i--)
  1685. if (data->edit.lines[i]->text == line)
  1686. break;
  1687. if (i < 0)
  1688. return GRUB_WIDGET_RESULT_DONE;
  1689. data->edit.line = i;
  1690. data->edit.pos = pos;
  1691. line[pos] = backup;
  1692. if (insert)
  1693. {
  1694. len = grub_strlen (line);
  1695. ilen = grub_strlen (insert);
  1696. size = (sizeof (struct grub_menu_region_text) + len + ilen
  1697. + 1 + 15) & ~15;
  1698. data->edit.lines[i] = grub_realloc (data->edit.lines[i], size);
  1699. if (! data->edit.lines[i])
  1700. return grub_errno;
  1701. line = data->edit.lines[i]->text;
  1702. for (i = len - 1; i >= pos; i--)
  1703. line[i + ilen] = line[i];
  1704. line[len + ilen] = 0;
  1705. for (i = 0; i < ilen; i++)
  1706. line[pos + i] = insert[i];
  1707. grub_free (insert);
  1708. data->edit.lines[data->edit.line]->common.width =
  1709. grub_menu_region_get_text_width (data->edit.lines[0]->font,
  1710. line, 0, 0);
  1711. }
  1712. else
  1713. ilen = 0;
  1714. text_width = update_x - data->edit.lines[data->edit.line]->common.ofs_x;
  1715. update_width = data->edit.lines[data->edit.line]->common.width
  1716. - text_width;
  1717. if (ilen)
  1718. {
  1719. text_width +=
  1720. grub_menu_region_get_text_width (data->edit.lines[0]->font,
  1721. line + pos, ilen, 0);
  1722. data->edit.pos += ilen;
  1723. }
  1724. if (edit_scroll_x (&data->edit, text_width, widget->width))
  1725. {
  1726. update_x = 0;
  1727. update_width = widget->width;
  1728. }
  1729. if (edit_scroll_y (&data->edit, widget->height))
  1730. {
  1731. update_x = 0;
  1732. update_y = 0;
  1733. update_width = widget->width;
  1734. update_height = widget->height;
  1735. }
  1736. else
  1737. update_height = data->edit.font_height;
  1738. draw_region (widget->node, update_x, update_y,
  1739. update_width, update_height);
  1740. return GRUB_WIDGET_RESULT_DONE;
  1741. }
  1742. else if (key == GRUB_TERM_CTRL_X)
  1743. return GRUB_WIDGET_RESULT_SKIP;
  1744. else
  1745. {
  1746. if (((has_prompt) &&
  1747. (data->edit.pos <= (int) sizeof (GRUB_PROMPT) - 1)) &&
  1748. (key == GRUB_TERM_BACKSPACE))
  1749. return GRUB_WIDGET_RESULT_DONE;
  1750. return edit_onkey (widget, key);
  1751. }
  1752. }
  1753. static struct grub_widget_class term_widget_class =
  1754. {
  1755. .name = "term",
  1756. .get_data_size = term_get_data_size,
  1757. .init_size = edit_init_size,
  1758. .free = term_free,
  1759. .draw = term_draw,
  1760. .draw_cursor = term_draw_cursor,
  1761. .onkey = term_onkey,
  1762. };
  1763. static grub_ssize_t
  1764. grub_gfxmenu_getcharwidth (grub_uint32_t c __attribute__((unused)))
  1765. {
  1766. return 1;
  1767. }
  1768. static grub_uint16_t
  1769. grub_gfxmenu_getwh (void)
  1770. {
  1771. int width;
  1772. if (cur_term)
  1773. {
  1774. struct edit_data *data;
  1775. data = cur_term->data;
  1776. width = cur_term->inner_width / data->font_width;
  1777. }
  1778. else
  1779. width = 0xff;
  1780. return (width << 8) + 0xff;
  1781. }
  1782. static grub_uint16_t
  1783. grub_gfxmenu_getxy (void)
  1784. {
  1785. struct edit_data *data;
  1786. if (! cur_term)
  1787. return 0;
  1788. data = cur_term->data;
  1789. return (data->pos << 8) | (data->line);
  1790. }
  1791. static void
  1792. grub_gfxmenu_gotoxy (grub_uint8_t x __attribute__((unused)), grub_uint8_t y)
  1793. {
  1794. struct edit_data *data;
  1795. if (! cur_term)
  1796. return;
  1797. data = cur_term->data;
  1798. if (y == data->line + 1)
  1799. edit_handle_key (cur_term, GRUB_TERM_DOWN);
  1800. }
  1801. static void
  1802. grub_gfxmenu_cls (void)
  1803. {
  1804. struct edit_data *data;
  1805. grub_font_t font;
  1806. int i;
  1807. if (! cur_term)
  1808. return;
  1809. data = cur_term->data;
  1810. data->x = 0;
  1811. data->y = 0;
  1812. data->pos = 0;
  1813. data->line = 0;
  1814. data->pos = 0;
  1815. font = data->lines[0]->font;
  1816. for (i = 0; i < data->num_lines; i++)
  1817. {
  1818. grub_menu_region_free ((grub_menu_region_common_t)
  1819. data->lines[i]);
  1820. data->lines[i] = 0;
  1821. }
  1822. data->lines[0] = grub_menu_region_create_text (font, 0, 0);
  1823. data->num_lines = 1;
  1824. grub_widget_draw (cur_term->node);
  1825. }
  1826. static void
  1827. grub_gfxmenu_setcolorstate (grub_term_color_state state)
  1828. {
  1829. (void) state;
  1830. }
  1831. static void
  1832. grub_gfxmenu_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color)
  1833. {
  1834. (void) normal_color;
  1835. (void) highlight_color;
  1836. }
  1837. static void
  1838. grub_gfxmenu_getcolor (grub_uint8_t *normal_color,
  1839. grub_uint8_t *highlight_color)
  1840. {
  1841. *normal_color = 0;
  1842. *highlight_color = 0;
  1843. }
  1844. static void
  1845. grub_gfxmenu_setcursor (int on)
  1846. {
  1847. cursor_off = ! on;
  1848. }
  1849. static void
  1850. grub_gfxmenu_refresh (void)
  1851. {
  1852. }
  1853. static void
  1854. grub_gfxmenu_putchar (grub_uint32_t c)
  1855. {
  1856. if (! cur_term)
  1857. return;
  1858. if (c == '\n')
  1859. edit_handle_key (cur_term, GRUB_TERM_DOWN);
  1860. else if (c != '\r')
  1861. {
  1862. int width;
  1863. struct edit_data *data;
  1864. data = cur_term->data;
  1865. width = data->x + data->font_width +
  1866. grub_menu_region_get_text_width (data->lines[0]->font,
  1867. (char *) &c, 1, 0);
  1868. if (width > cur_term->width)
  1869. edit_handle_key (cur_term, GRUB_TERM_DOWN);
  1870. edit_handle_key (cur_term, c);
  1871. }
  1872. }
  1873. struct grub_term_output grub_gfxmenu_term =
  1874. {
  1875. .name = "gfxmenu",
  1876. .putchar = grub_gfxmenu_putchar,
  1877. .getcharwidth = grub_gfxmenu_getcharwidth,
  1878. .getwh = grub_gfxmenu_getwh,
  1879. .getxy = grub_gfxmenu_getxy,
  1880. .gotoxy = grub_gfxmenu_gotoxy,
  1881. .cls = grub_gfxmenu_cls,
  1882. .setcolorstate = grub_gfxmenu_setcolorstate,
  1883. .setcolor = grub_gfxmenu_setcolor,
  1884. .getcolor = grub_gfxmenu_getcolor,
  1885. .setcursor = grub_gfxmenu_setcursor,
  1886. .refresh = grub_gfxmenu_refresh,
  1887. .flags = 0,
  1888. .next = 0
  1889. };
  1890. GRUB_MOD_INIT(coreui)
  1891. {
  1892. grub_widget_class_register (&screen_widget_class);
  1893. grub_widget_class_register (&panel_widget_class);
  1894. grub_widget_class_register (&image_widget_class);
  1895. grub_widget_class_register (&text_widget_class);
  1896. grub_widget_class_register (&password_widget_class);
  1897. grub_widget_class_register (&progressbar_widget_class);
  1898. grub_widget_class_register (&circular_progress_widget_class);
  1899. grub_widget_class_register (&edit_widget_class);
  1900. grub_widget_class_register (&term_widget_class);
  1901. grub_term_register_output ("gfxmenu", &grub_gfxmenu_term);
  1902. }
  1903. GRUB_MOD_FINI(coreui)
  1904. {
  1905. grub_widget_class_unregister (&screen_widget_class);
  1906. grub_widget_class_unregister (&panel_widget_class);
  1907. grub_widget_class_unregister (&image_widget_class);
  1908. grub_widget_class_unregister (&text_widget_class);
  1909. grub_widget_class_unregister (&password_widget_class);
  1910. grub_widget_class_unregister (&progressbar_widget_class);
  1911. grub_widget_class_unregister (&circular_progress_widget_class);
  1912. grub_widget_class_unregister (&edit_widget_class);
  1913. grub_widget_class_unregister (&term_widget_class);
  1914. grub_term_unregister_output (&grub_gfxmenu_term);
  1915. }