gtk_demo.pas 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  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.