2
0

gtk_demo.pas 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  1. (* GTK Demo for Pascal
  2. *
  3. * Welcome to GTK Demo for Pascal.
  4. *
  5. *
  6. * This demo is an adaption of the GTK Demo included in the GTK+-2.0 source.
  7. * A new feature is syntax highligting for pascal.
  8. *)
  9. program gtk_demo;
  10. {$mode objfpc} {$H+}
  11. uses glib2, pango, gdk2, gtk2, gdk2pixbuf, strings, math;
  12. var
  13. info_buffer : PGtkTextBuffer;
  14. source_buffer : PGtkTextBuffer;
  15. current_file : pgchar;
  16. type
  17. TFileOfChar = file of char;
  18. TGDoDemoFunc = function : PGtkWidget;
  19. PDemo = ^TDemo;
  20. TDemo = record
  21. title : pgchar;
  22. filename : pgchar;
  23. func : TGDoDemoFunc;
  24. children : PDemo;
  25. end;
  26. PCallbackData = ^TCallbackData;
  27. TCallbackData = record
  28. model : PGtkTreeModel;
  29. path : PGtkTreePath;
  30. end;
  31. const
  32. DEMO_DATA_DIR = 'data';
  33. TITLE_COLUMN = 0;
  34. FILENAME_COLUMN = 1;
  35. FUNC_COLUMN = 2;
  36. ITALIC_COLUMN = 3;
  37. NUM_COLUMNS = 4;
  38. STATE_NORMAL = 0;
  39. STATE_IN_COMMENT = 1;
  40. function demo_find_file ( base : pchar; err : PPGError): pgchar; forward;
  41. (* file_is_valid
  42. * a dirty little hack to find out if a file variable is assigned and the
  43. * file is opened.
  44. *)
  45. function file_is_valid (var f: file): boolean;
  46. begin
  47. {$I-}
  48. if eof(f) then
  49. exit (TRUE);
  50. {$I+}
  51. if IOResult <> 0 then
  52. file_is_valid := FALSE
  53. else
  54. file_is_valid := TRUE;
  55. end;
  56. (* min, max
  57. * these two functions of the math unit are overloaded to understand double
  58. * values.
  59. *)
  60. function min (d1, d2: double): double;
  61. begin
  62. if d1 > d2 then min := d2
  63. else min := d1;
  64. end;
  65. function max (d1, d2: double): double;
  66. begin
  67. if d1 < d2 then max := d2
  68. else max := d1;
  69. end;
  70. (* do_dummy
  71. * creates a widget informing the user that the demo isn't implemented, yet
  72. *)
  73. procedure do_dummy (demo : pgchar);
  74. var
  75. dialog : PGtkWidget;
  76. begin
  77. dialog := gtk_message_dialog_new (NULL, 0,
  78. GTK_MESSAGE_INFO,
  79. GTK_BUTTONS_CLOSE,
  80. 'Sorry, "%s" is''t implemented, yet.',
  81. [demo]);
  82. gtk_widget_show (dialog);
  83. g_signal_connect (dialog, 'response',
  84. G_CALLBACK (@gtk_widget_destroy), NULL);
  85. end;
  86. (* include the modules here;
  87. * if you'd like to add one add the include command and
  88. * create a new entry in the testgtk_demos array
  89. *)
  90. {$include appwindow.inc}
  91. {$include button_box.inc}
  92. {$include colorsel.inc}
  93. {$include dialog.inc}
  94. {$include drawingarea.inc}
  95. {$include editable_cells.inc}
  96. {$include images.inc}
  97. {$include item_factory.inc}
  98. {$include list_store.inc}
  99. {$include menus.inc}
  100. {$include panes.inc}
  101. {$include pixbufs.inc}
  102. {$include sizegroup.inc}
  103. {$include stock_browser.inc}
  104. {$include textview.inc}
  105. {$include tree_store.inc}
  106. const
  107. child0 : array [1..4] of TDemo = (
  108. (title: 'Editable Cells'; filename: 'editable_cells.inc'; func: @do_editable_cells; children: nil),
  109. (title: 'List Store'; filename: 'list_store.inc'; func: @do_list_store; children: nil),
  110. (title: 'Tree Store'; filename: 'tree_store.inc'; func: @do_tree_store; children: nil),
  111. (title: nil; filename: nil; func: nil; children: nil));
  112. testgtk_demos: array [1..16] of TDemo = (
  113. (title: '* This Application *'; filename: 'gtk_demo.pas'; func: nil; children: nil),
  114. (title: 'Application main window'; filename: 'appwindow.inc'; func: @do_appwindow; children: nil),
  115. (title: 'Button Boxes'; filename: 'button_box.inc'; func: @do_button_box; children: nil),
  116. (title: 'Color Selector'; filename: 'colorsel.inc'; func: @do_colorsel; children: nil),
  117. (title: 'Dialog and Message Boxes'; filename: 'dialog.inc'; func: @do_dialog; children: nil),
  118. (title: 'Drawing Area'; filename: 'drawingarea.inc'; func: @do_drawingarea; children: nil),
  119. (title: 'Images'; filename: 'images.inc'; func: @do_images; children: nil),
  120. (title: 'Item Factory'; filename: 'item_factory.inc'; func: @do_item_factory; children: nil),
  121. (title: 'Menus'; filename: 'menus.inc'; func: @do_menus; children: nil),
  122. (title: 'Paned Widgets'; filename: 'panes.inc'; func: @do_panes; children: nil),
  123. (title: 'Pixbufs'; filename: 'pixbufs.inc'; func: @do_pixbufs; children: nil),
  124. (title: 'Size Groups'; filename: 'sizegroup.inc'; func: @do_sizegroup; children: nil),
  125. (title: 'Stock Item and Icon Browser'; filename: 'stock_browser.inc'; func: @do_stock_browser; children: nil),
  126. (title: 'Text Widget'; filename: 'textview.inc'; func: @do_textview; children: nil),
  127. (title: 'Tree View'; filename: nil; func: nil; children: @child0),
  128. (title: nil; filename: nil; func: nil; children: nil));
  129. function demo_find_file ( base : pchar;
  130. err : PPGError): pgchar;
  131. var
  132. filename : pchar;
  133. begin
  134. if g_file_test (base, G_FILE_TEST_EXISTS) then begin
  135. demo_find_file := g_strdup (base);
  136. exit;
  137. end else
  138. begin
  139. filename := g_build_filename (DEMO_DATA_DIR, [ base, NULL ]);
  140. if not (g_file_test (filename, G_FILE_TEST_EXISTS)) then
  141. begin
  142. g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_NOENT,
  143. 'Cannot find demo data file "%s"', [base]);
  144. g_free (filename);
  145. demo_find_file := NULL;
  146. end else
  147. demo_find_file := filename;
  148. end;
  149. end;
  150. function create_text (var buffer : PGtkTextBuffer;
  151. is_source : gboolean): PGtkWidget;
  152. var
  153. scrolled_window,
  154. text_view : PGtkWidget;
  155. font_desc : PPangoFontDescription;
  156. begin
  157. scrolled_window := gtk_scrolled_window_new (NULL, NULL);
  158. gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
  159. GTK_POLICY_AUTOMATIC,
  160. GTK_POLICY_AUTOMATIC);
  161. gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
  162. GTK_SHADOW_IN);
  163. text_view := gtk_text_view_new;
  164. buffer := gtk_text_buffer_new (NULL);
  165. gtk_text_view_set_buffer (GTK_TEXT_VIEW (text_view), buffer);
  166. gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
  167. gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE);
  168. gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
  169. if is_source then
  170. begin
  171. font_desc := pango_font_description_from_string ('Courier 12');
  172. gtk_widget_modify_font (text_view, font_desc);
  173. pango_font_description_free (font_desc);
  174. gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
  175. GTK_WRAP_NONE);
  176. end else
  177. begin
  178. (* Make it a bit nicer for text. *)
  179. gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view),
  180. GTK_WRAP_WORD);
  181. gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (text_view), 2);
  182. gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (text_view), 2);
  183. end;
  184. create_text := scrolled_window;
  185. end;
  186. const
  187. tokens: array [1..4] of pgchar =
  188. ('(*',
  189. '''',
  190. '{',
  191. '//');
  192. types: array [1..57] of pgchar =
  193. ('integer',
  194. 'gchar',
  195. 'pgchar',
  196. 'char',
  197. 'gfloat',
  198. 'real',
  199. 'gint8',
  200. 'gint16',
  201. 'gint32',
  202. 'gint',
  203. 'guint',
  204. 'guint8',
  205. 'guint16',
  206. 'guint32',
  207. 'guchar',
  208. 'glong',
  209. 'longint',
  210. 'gboolean' ,
  211. 'gshort',
  212. 'gushort',
  213. 'gulong',
  214. 'gdouble',
  215. 'double',
  216. 'gldouble',
  217. 'gpointer',
  218. 'pointer',
  219. 'NULL',
  220. 'nil',
  221. 'PGList',
  222. 'TGList',
  223. 'TGSList',
  224. 'PGSList',
  225. 'FALSE',
  226. 'TRUE',
  227. 'PGtkObject',
  228. 'TGtkObject',
  229. 'TGtkColorSelection',
  230. 'PGtkColorSelection',
  231. 'PGtkWidget',
  232. 'TGtkWidget',
  233. 'PGtkButton',
  234. 'TGtkButton',
  235. 'TGdkColor',
  236. 'PGdkColor',
  237. 'TGdkRectangle',
  238. 'PGdkRectangle',
  239. 'TGdkEventExpose',
  240. 'PGdkEventExpose',
  241. 'TGdkGC',
  242. 'PGdkGC',
  243. 'TGdkPixbufLoader',
  244. 'PGdkPixbufLoader',
  245. 'TGdkPixbuf',
  246. 'PGdkPixbuf',
  247. 'PPGError',
  248. 'PGError',
  249. 'array');
  250. control: array [1..23] of pgchar = (
  251. 'if',
  252. 'then',
  253. 'case',
  254. 'while',
  255. 'else',
  256. 'do',
  257. 'for',
  258. 'begin',
  259. 'end',
  260. 'exit',
  261. 'goto',
  262. 'program',
  263. 'unit',
  264. 'library',
  265. 'procedure',
  266. 'function',
  267. 'type',
  268. 'var',
  269. 'const',
  270. 'record',
  271. 'uses',
  272. 'of',
  273. 'in');
  274. procedure parse_chars ( text : pgchar;
  275. var end_ptr : pgchar;
  276. var state : gint;
  277. var tag : pgchar;
  278. start : gboolean);
  279. var
  280. i : gint;
  281. next_token : pgchar;
  282. maybe_escape : boolean;
  283. begin
  284. (* leave out leading spaces *)
  285. while (text^ <> #0) and (g_ascii_isspace (text^)) do
  286. inc (text);
  287. (* Handle comments first *)
  288. if state = STATE_IN_COMMENT then
  289. begin
  290. end_ptr := StrPos (text, '*)');
  291. next_token := StrPos (text, '}');
  292. if next_token > end_ptr then begin
  293. end_ptr := next_token + 1; // '}' comment type
  294. state := STATE_NORMAL;
  295. tag := 'comment';
  296. end else
  297. if end_ptr <> NULL then
  298. begin
  299. end_ptr := end_ptr + 2; // '* )' comment type
  300. state := STATE_NORMAL;
  301. tag := 'comment';
  302. end;
  303. exit;
  304. end;
  305. tag := NULL;
  306. end_ptr := NULL;
  307. if text^ = #0 then
  308. exit;
  309. (* check for preprocessor defines *)
  310. if (((StrLComp (text, '(*', 2)) = 0) and (text[2] = '$') ) or
  311. (((StrLComp (text, '{', 1)) = 0) and (text[1] = '$') ) then
  312. begin
  313. end_ptr := StrPos (text, '*)');
  314. next_token := StrPos (text, '}');
  315. if next_token > end_ptr then
  316. end_ptr := next_token + 1
  317. else
  318. if end_ptr <> NULL then
  319. end_ptr := end_ptr + 2;
  320. tag := 'preprocessor';
  321. exit;
  322. end;
  323. (* check for comment *)
  324. if ((StrLComp (text, '(*', 2)) = 0) or
  325. ((StrLComp (text, '{', 1)) = 0) then
  326. begin
  327. end_ptr := StrPos (text, '*)');
  328. next_token := StrPos (text, '}');
  329. if next_token > end_ptr then
  330. end_ptr := next_token+1
  331. else begin
  332. if end_ptr <> NULL then
  333. end_ptr := end_ptr + 2
  334. else
  335. state := STATE_IN_COMMENT;
  336. end;
  337. tag := 'comment';
  338. exit;
  339. end;
  340. if (StrLComp (text, '//', 2)) = 0 then
  341. begin
  342. end_ptr := NULL;
  343. tag := 'comment';
  344. exit;
  345. end;
  346. (* check for types *)
  347. for i := 1 to high (types) do
  348. if ((StrLComp (text, types[i], strlen (types[i]))) = 0 ) and
  349. ((text+strlen(types[i]))^ in [#8, #32, #0, ';', #13, #10, ')', ']', ':']) then
  350. begin
  351. end_ptr := text + strlen (types[i]);
  352. tag := 'type';
  353. exit;
  354. end;
  355. (* check for control *)
  356. for i := 1 to high (control) do begin
  357. if ((StrLComp (text, control[i], strlen (control[i]))) = 0) and
  358. ((text+strlen(control[i]))^ in [#8, #32, #0, ';', #13, #10, ')', ']', ':']) then
  359. begin
  360. end_ptr := text + strlen (control[i]);
  361. tag := 'control';
  362. exit;
  363. end;
  364. end;
  365. (* check for string *)
  366. if text^= '''' then
  367. begin
  368. maybe_escape := FALSE;
  369. end_ptr := text + 1;
  370. tag := 'string';
  371. while end_ptr^ <> #0 do
  372. begin
  373. if (end_ptr^ = '''') and (maybe_escape = FALSE) then
  374. begin
  375. inc (end_ptr);
  376. exit;
  377. end;
  378. if end_ptr^ = '\' then
  379. maybe_escape := TRUE
  380. else
  381. maybe_escape := FALSE;
  382. inc (end_ptr);
  383. end;
  384. exit;
  385. end;
  386. (* not at the start of a tag. Find the next one. *)
  387. for i := 1 to high(tokens) do
  388. begin
  389. next_token := StrPos (text, tokens[i]);
  390. if next_token <> NULL then
  391. begin
  392. if end_ptr <> NULL then
  393. begin
  394. if end_ptr > next_token then
  395. end_ptr := next_token;
  396. end else
  397. end_ptr := next_token;
  398. end;
  399. end;
  400. for i := 1 to high(types) do
  401. begin
  402. next_token := StrPos (text, types[i]);
  403. if next_token <> NULL then
  404. if ( (next_token+strlen(types[i]))^
  405. in [#8, #32, #0, ';', #13, #10, ')', ']', ':']) and
  406. g_ascii_isspace ((next_token-1)^) then
  407. begin
  408. if end_ptr <> NULL then
  409. begin
  410. if end_ptr > next_token then
  411. end_ptr := next_token;
  412. end else
  413. end_ptr := next_token;
  414. end;
  415. end;
  416. for i := 1 to high(control) do
  417. begin
  418. next_token := StrPos (text, control[i]);
  419. if next_token <> NULL then
  420. if ( (next_token+strlen(control[i]))^
  421. in [#8, #32, #0, ';', #13, #10, ')', ']', ':']) and
  422. g_ascii_isspace ((next_token-1)^) then
  423. begin
  424. if end_ptr <> NULL then
  425. begin
  426. if end_ptr > next_token then
  427. end_ptr := next_token;
  428. end else
  429. end_ptr := next_token;
  430. end;
  431. end;
  432. end;
  433. (* While not as cool as c-mode, this will do as a quick attempt at highlighting *)
  434. procedure fontify;
  435. var
  436. start_iter,
  437. next_iter,
  438. tmp_iter : TGtkTextIter;
  439. state : gint;
  440. text : pgchar;
  441. start_ptr,
  442. end_ptr : pgchar;
  443. tag : pgchar;
  444. start : gboolean;
  445. begin
  446. state := STATE_NORMAL;
  447. gtk_text_buffer_get_iter_at_offset (source_buffer, @start_iter, 0);
  448. next_iter := start_iter;
  449. while (gtk_text_iter_forward_line (@next_iter)) do
  450. begin
  451. start := TRUE;
  452. text := gtk_text_iter_get_text ( @start_iter, @next_iter);
  453. start_ptr := text;
  454. repeat
  455. parse_chars (start_ptr, end_ptr, state, tag, start);
  456. start := FALSE;
  457. if end_ptr <> NULL then begin
  458. tmp_iter := start_iter;
  459. gtk_text_iter_forward_chars (@tmp_iter, end_ptr - start_ptr);
  460. end else
  461. tmp_iter := next_iter;
  462. if tag <> NULL then
  463. gtk_text_buffer_apply_tag_by_name (source_buffer, tag, @start_iter, @tmp_iter);
  464. start_iter := tmp_iter;
  465. start_ptr := end_ptr;
  466. until end_ptr = NULL;
  467. g_free (text);
  468. start_iter := next_iter;
  469. end;
  470. end;
  471. function read_line (var f: TFileOfChar; str: PGString): boolean;
  472. var
  473. n_read : integer;
  474. c,
  475. next_c : char;
  476. begin
  477. n_read := 0;
  478. g_string_truncate (str, 0);
  479. while not eof(f) do begin
  480. read (f, c);
  481. inc (n_read);
  482. if (c = #10) or (c = #13) then
  483. begin
  484. if not eof(f) then
  485. begin
  486. read (f, next_c);
  487. if not ((next_c in [#13, #10]) and (c <> next_c)) then
  488. seek(f, filepos(f)-1);
  489. break;
  490. end;
  491. end else
  492. g_string_append_c (str, c);
  493. end;
  494. read_line := n_read > 0;
  495. end;
  496. (* opens a textfile and reads it into the TGtkTextBuffer *)
  497. procedure load_file (filename : pgchar);
  498. var
  499. text_start,
  500. text_end : TGtkTextIter;
  501. err : PGError;
  502. buffer : PGString;
  503. state,
  504. len_chars,
  505. len : integer;
  506. in_para : gboolean;
  507. f : TFileOfChar;
  508. full_name : pchar;
  509. p, q, r : pgchar;
  510. begin
  511. err := NULL;
  512. buffer := g_string_new (NULL);
  513. state := 0;
  514. in_para := FALSE;
  515. if (current_file <> NULL) and (StrComp (current_file, filename) = 0) then begin
  516. g_string_free (buffer, TRUE);
  517. exit;
  518. end;
  519. g_free (current_file);
  520. current_file := g_strdup (filename);
  521. gtk_text_buffer_get_bounds (info_buffer, @text_start, @text_end);
  522. gtk_text_buffer_delete (info_buffer, @text_start, @text_end);
  523. gtk_text_buffer_get_bounds (source_buffer, @text_start, @text_end);
  524. gtk_text_buffer_delete (source_buffer, @text_start, @text_end);
  525. full_name := demo_find_file (filename, @err);
  526. if full_name = NULL then begin
  527. g_warning ('%s', [err^.message]);
  528. g_error_free (err);
  529. exit;
  530. end;
  531. {$I-}
  532. assign (f, full_name);
  533. reset (f);
  534. {$I+}
  535. if IOResult <> 0 then
  536. g_print ('Cannot open %s: file not found'#13#10, [full_name]);
  537. g_free (full_name);
  538. if IOResult <> 0 then
  539. exit;
  540. gtk_text_buffer_get_iter_at_offset (info_buffer, @text_start, 0);
  541. while read_line (f, buffer) do
  542. begin
  543. p := buffer^.str;
  544. case state of
  545. 0 : begin (* Reading title *)
  546. while (((p^ = '(') or (p^ = '*')) or (p^ = '{')) or g_ascii_isspace (p^) do
  547. inc (p);
  548. r := p;
  549. while (r^ <> ')') and (strlen (r) > 0) do
  550. inc (r);
  551. if strlen (r) > 0 then
  552. p := r + 1;
  553. q := p + strlen (p);
  554. while (q > p) and g_ascii_isspace ((q - 1)^) do
  555. dec(q);
  556. if q > p then
  557. begin
  558. len_chars := g_utf8_pointer_to_offset (p, q);
  559. text_end := text_start;
  560. // g_assert (strlen (p) >= (q - p));
  561. gtk_text_buffer_insert (info_buffer, @text_end, p, q - p);
  562. text_start := text_end;
  563. gtk_text_iter_backward_chars (@text_start, len_chars);
  564. gtk_text_buffer_apply_tag_by_name (info_buffer, 'title', @text_start, @text_end);
  565. text_start := text_end;
  566. inc (state);
  567. end; {of q > p }
  568. end; {of state = 0}
  569. 1: begin (* Reading body of info section *)
  570. while g_ascii_isspace (p^) do
  571. inc(p);
  572. if (p^ = '*') and ((p + 1)^ = ')') then
  573. begin
  574. gtk_text_buffer_get_iter_at_offset (source_buffer, @text_start, 0);
  575. inc(state);
  576. end else
  577. begin
  578. while (p^ = '*') or g_ascii_isspace (p^) do
  579. inc(p);
  580. len := strlen (p);
  581. while g_ascii_isspace ( (p + len - 1)^) do
  582. dec (len);
  583. if len > 0 then
  584. begin
  585. if in_para then
  586. gtk_text_buffer_insert (info_buffer, @text_start, ' ', 1);
  587. // g_assert (strlen (p) >= len);
  588. gtk_text_buffer_insert (info_buffer, @text_start, p, len);
  589. in_para := TRUE;
  590. end else
  591. begin
  592. gtk_text_buffer_insert (info_buffer, @text_start, #10, 1);
  593. in_para := FALSE;
  594. end; {else len <= 0}
  595. end;
  596. end;
  597. 2: begin (* Skipping blank lines *)
  598. while g_ascii_isspace (p^) do
  599. inc(p);
  600. if p^ <> #0 then
  601. begin
  602. p := buffer^.str;
  603. inc (state); (* Fall through *)
  604. (* Reading program body *)
  605. gtk_text_buffer_insert (source_buffer, @text_start, p, -1);
  606. gtk_text_buffer_insert (source_buffer, @text_start, #10, 1);
  607. end;
  608. end;
  609. 3: begin (* Reading program body *)
  610. gtk_text_buffer_insert (source_buffer, @text_start, p, -1);
  611. gtk_text_buffer_insert (source_buffer, @text_start, #10, 1);
  612. end;
  613. end;
  614. end;
  615. close (f);
  616. fontify ();
  617. g_string_free (buffer, TRUE);
  618. end;
  619. (* some callbacks *)
  620. procedure window_closed_cb (window : PGtkWidget;
  621. data : gpointer); cdecl;
  622. var
  623. cbdata : PCallbackData;
  624. iter : TGtkTreeIter;
  625. italic,
  626. nitalic : gboolean;
  627. begin
  628. cbdata := data;
  629. gtk_tree_model_get_iter (cbdata^.model, @iter, cbdata^.path);
  630. gtk_tree_model_get (GTK_TREE_MODEL (cbdata^.model), @iter,
  631. [ ITALIC_COLUMN, @italic, -1] );
  632. nitalic := not italic;
  633. if italic then
  634. gtk_tree_store_set (GTK_TREE_STORE (cbdata^.model), @iter,
  635. [ ITALIC_COLUMN, nitalic, -1] );
  636. gtk_tree_path_free (cbdata^.path);
  637. dispose (cbdata);
  638. end;
  639. procedure row_activated_cb (tree_view : PGtkTreeView;
  640. path : PGtkTreePath;
  641. column : PGtkTreeViewColumn); cdecl;
  642. var
  643. iter : TGtkTreeIter;
  644. italic,
  645. nitalic : gboolean;
  646. func : TGDoDemoFunc;
  647. window : PGtkWidget;
  648. model : PGtkTreeModel;
  649. cbdata : PCallbackData;
  650. begin
  651. model := gtk_tree_view_get_model (tree_view);
  652. gtk_tree_model_get_iter (model, @iter, path);
  653. gtk_tree_model_get (GTK_TREE_MODEL (model),
  654. @iter,
  655. [ FUNC_COLUMN, @func,
  656. ITALIC_COLUMN, @italic, -1 ]);
  657. if func <> NULL then
  658. begin
  659. nitalic := not italic;
  660. gtk_tree_store_set (GTK_TREE_STORE (model),
  661. @iter,
  662. [ ITALIC_COLUMN, nitalic, -1 ] );
  663. window := func();
  664. if window <> NULL then
  665. begin
  666. new (cbdata);
  667. cbdata^.model := model;
  668. cbdata^.path := gtk_tree_path_copy (path);
  669. g_signal_connect (window, 'destroy',
  670. G_CALLBACK (@window_closed_cb), cbdata );
  671. end;
  672. end;
  673. end;
  674. procedure selection_cb ( selection : PGtkTreeSelection;
  675. model : PGtkTreeModel); cdecl;
  676. var
  677. iter : TGtkTreeIter;
  678. // value : TGValue;
  679. str : pgchar;
  680. begin
  681. (* g_value_init(@value, G_TYPE_STRING); // added to test if TGValue works
  682. // -- its seems not as if it does *)
  683. if not gtk_tree_selection_get_selected (selection, NULL, @iter) then
  684. exit;
  685. (* The original code used TGValue but it seems not to work; check why *)
  686. (*
  687. gtk_tree_model_get_value (model, @iter, FILENAME_COLUMN, @value);
  688. if (g_value_get_string (@value)) <> NULL then
  689. load_file (g_value_get_string (@value));
  690. g_value_unset (@value);
  691. *)
  692. gtk_tree_model_get (model, @iter, [FILENAME_COLUMN, @str, -1]);
  693. if str <> NULL then
  694. load_file (str);
  695. end;
  696. function create_tree: PGtkWidget;
  697. var
  698. selection : PGtkTreeSelection;
  699. cell : PGtkCellRenderer;
  700. tree_view : PGtkWidget;
  701. column : PGtkTreeViewColumn;
  702. model : PGtkTreeStore;
  703. iter,
  704. child_iter : TGtkTreeIter;
  705. d,
  706. children : PDemo;
  707. begin
  708. d := @testgtk_demos;
  709. model := gtk_tree_store_new (NUM_COLUMNS, [G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN]);
  710. tree_view := gtk_tree_view_new ();
  711. gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model));
  712. selection := gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
  713. gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
  714. GTK_SELECTION_BROWSE);
  715. gtk_widget_set_size_request (tree_view, 200, -1);
  716. (* this code only supports 1 level of children. If we
  717. * want more we probably have to use a recursing function.
  718. *)
  719. while d^.title <> NULL do begin
  720. children := d^.children;
  721. gtk_tree_store_append (GTK_TREE_STORE (model), @iter, NULL);
  722. gtk_tree_store_set (GTK_TREE_STORE (model),
  723. @iter,
  724. [ TITLE_COLUMN, d^.title,
  725. FILENAME_COLUMN, d^.filename,
  726. FUNC_COLUMN, d^.func,
  727. ITALIC_COLUMN, FALSE, -1 ] );
  728. inc(d);
  729. if children = NULL then
  730. continue;
  731. while children^.title <> NULL do begin
  732. gtk_tree_store_append (GTK_TREE_STORE (model), @child_iter, @iter);
  733. gtk_tree_store_set (GTK_TREE_STORE (model),
  734. @child_iter,
  735. [TITLE_COLUMN, children^.title,
  736. FILENAME_COLUMN, children^.filename,
  737. FUNC_COLUMN, children^.func,
  738. ITALIC_COLUMN, FALSE, -1]);
  739. inc (children);
  740. end;
  741. end;
  742. cell := gtk_cell_renderer_text_new ();
  743. g_object_set (G_OBJECT (cell),
  744. 'style', [ PANGO_STYLE_ITALIC, NULL ]);
  745. column := gtk_tree_view_column_new_with_attributes ('Widget (double click for demo)',
  746. cell,
  747. [ 'text', TITLE_COLUMN,
  748. 'style_set', ITALIC_COLUMN, NULL ] );
  749. gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
  750. GTK_TREE_VIEW_COLUMN (column));
  751. g_signal_connect (selection, 'changed', G_CALLBACK (@selection_cb), model);
  752. g_signal_connect (tree_view, 'row_activated', G_CALLBACK (@row_activated_cb), model);
  753. gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
  754. create_tree := tree_view;
  755. end;
  756. procedure setup_default_icon;
  757. var
  758. pixbuf : PGdkPixbuf;
  759. filename : pchar;
  760. err : PGError;
  761. dialog : PGtkWidget;
  762. list : PGList;
  763. transparent : PGdkPixbuf;
  764. begin
  765. err := NULL;
  766. pixbuf := NULL;
  767. dialog := NULL;
  768. filename := demo_find_file ('gtk-logo-rgb.gif', @err);
  769. if filename <> NULL then
  770. begin
  771. pixbuf := gdk_pixbuf_new_from_file (filename, @err);
  772. g_free (filename);
  773. end;
  774. (* Ignoring this error (passing NULL instead of &err above)
  775. * would probably be reasonable for most apps. We're just
  776. * showing off.
  777. *)
  778. if err <> NULL then
  779. begin
  780. dialog := gtk_message_dialog_new (NULL, 0,
  781. GTK_MESSAGE_ERROR,
  782. GTK_BUTTONS_CLOSE,
  783. 'Failed to read icon file: %s',
  784. [err^.message]);
  785. gtk_widget_show (dialog);
  786. g_error_free (err);
  787. g_signal_connect (dialog, 'response',
  788. G_CALLBACK (@gtk_widget_destroy), NULL);
  789. end;
  790. if pixbuf <> NULL then
  791. begin
  792. (* The gtk-logo-rgb icon has a white background, make it transparent *)
  793. transparent := gdk_pixbuf_add_alpha (pixbuf, TRUE, $ff, $ff, $ff);
  794. list := NULL;
  795. list := g_list_append (list, transparent);
  796. gtk_window_set_default_icon_list (list);
  797. g_list_free (list);
  798. g_object_unref (G_OBJECT (pixbuf));
  799. g_object_unref (G_OBJECT (transparent));
  800. end;
  801. end;
  802. var
  803. window,
  804. notebook,
  805. hbox,
  806. tree : PGtkWidget;
  807. begin
  808. current_file := NULL;
  809. {$include init.inc} (* contains all variable inits of the demos *)
  810. gtk_init (@argc, @argv);
  811. setup_default_icon ();
  812. window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
  813. gtk_window_set_title (GTK_WINDOW (window), 'GTK+ Code Demos');
  814. g_signal_connect (window, 'destroy',
  815. G_CALLBACK (@gtk_main_quit), NULL);
  816. hbox := gtk_hbox_new (FALSE, 0);
  817. gtk_container_add (GTK_CONTAINER (window), hbox);
  818. tree := create_tree;
  819. gtk_box_pack_start (GTK_BOX (hbox), tree, FALSE, FALSE, 0);
  820. notebook := gtk_notebook_new;
  821. gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
  822. gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
  823. create_text (info_buffer, FALSE),
  824. gtk_label_new_with_mnemonic ('_Info'));
  825. gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
  826. create_text (source_buffer, TRUE),
  827. gtk_label_new_with_mnemonic ('_Source'));
  828. gtk_text_buffer_create_tag (info_buffer, 'title', 'font', ['Sans 18', NULL ]);
  829. gtk_text_buffer_create_tag (source_buffer, 'comment', 'foreground', ['red', NULL]);
  830. gtk_text_buffer_create_tag (source_buffer, 'type', 'foreground', ['ForestGreen', NULL]);
  831. gtk_text_buffer_create_tag (source_buffer, 'string', 'foreground',
  832. ['RosyBrown', 'weight', PANGO_WEIGHT_BOLD, NULL]);
  833. gtk_text_buffer_create_tag (source_buffer, 'control', 'foreground', ['purple', NULL]);
  834. gtk_text_buffer_create_tag (source_buffer, 'preprocessor', 'style',
  835. [ PANGO_STYLE_OBLIQUE, 'foreground', 'blue', NULL] );
  836. gtk_text_buffer_create_tag (source_buffer, 'function', 'weight',
  837. [ PANGO_WEIGHT_BOLD, 'foreground', 'DarkGoldenrod4', NULL]);
  838. gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
  839. gtk_widget_show_all (window);
  840. gtk_main;
  841. end.