summaryrefslogtreecommitdiff
path: root/lib/utilities/notes.tcl
blob: 333dba9ab9eb5a9caa70aaa8662e08071e38dcf3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
#!/usr/bin/tclsh
# Part of MCU 8051 IDE ( http://http://www.moravia-microsystems.com/mcu8051ide )

############################################################################
#    Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 by Martin Ošmera     #
#    martin.osmera@gmail.com                                               #
#                                                                          #
#    Copyright (C) 2014 by Moravia Microsystems, s.r.o.                    #
#    martin.osmera@moravia-microsystems.com                                #
#                                                                          #
#    This program is free software; you can redistribute it and#or modify  #
#    it under the terms of the GNU General Public License as published by  #
#    the Free Software Foundation; either version 2 of the License, or     #
#    (at your option) any later version.                                   #
#                                                                          #
#    This program is distributed in the hope that it will be useful,       #
#    but WITHOUT ANY WARRANTY; without even the implied warranty of        #
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
#    GNU General Public License for more details.                          #
#                                                                          #
#    You should have received a copy of the GNU General Public License     #
#    along with this program; if not, write to the                         #
#    Free Software Foundation, Inc.,                                       #
#    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             #
############################################################################

# >>> File inclusion guard
if { ! [ info exists _NOTES_TCL ] } {
set _NOTES_TCL _
# <<< File inclusion guard

# --------------------------------------------------------------------------
# DESCRIPTION:
# Scribble notes independent on project
# --------------------------------------------------------------------------

class Notes {
	## COMMON
	public common count	0			;# Int: Counter of object instances
	public common bgcolor	{#EEEE55}		;# Color: Background color for title bar and window border
	public common bgcolor2	{#FFFF88}		;# Color: Background color for the canvas widget
	# Font: For inserted text
	public common canvas_text_font [font create			\
		-family $::DEFAULT_FIXED_FONT			\
		-size [expr {int(-14 * $::font_size_factor)}]	\
		-weight bold					\
	]
	# List: Popup menu for the canvas widget
	public common MENU {
		{radiobutton	"Pencil"	{}	::Notes::__mode		{P}
			"change_mode P"		0}
		{radiobutton	"Line"		{}	::Notes::__mode		{L}
			"change_mode L"		0}
		{radiobutton	"Arrow"		{}	::Notes::__mode		{A}
			"change_mode A"		0}
		{radiobutton	"Rectangle"	{}	::Notes::__mode		{R}
			"change_mode R"		0}
		{radiobutton	"Oval"		{}	::Notes::__mode		{O}
			"change_mode O"		0}
		{radiobutton	"Insert text"	{}	::Notes::__mode		{T}
			"change_mode T"		0}
		{radiobutton	"Move canvas"	{}	::Notes::__mode		{M}
			"change_mode M"		0}
		{radiobutton	"Eraser"	{}	::Notes::__mode		{C}
			"change_mode C"		0}
		{separator}
		{command	"Zoom in"	""	0	{canvas_zoom_in_from_pmenu}
			{viewmag_in}}
		{command	"Zoom out"	""	0	{canvas_zoom_out_from_pmenu}
			{viewmag_out}}
		{separator}
		{command	"Insert image"	""	0	{load_image}
			{fileimport}}
		{command	"Select color"	""	0	{select_color}
			{colorize}}
		{separator}
		{command	"Clear all"	""	0	{canvas_clear_all}
			{emptytrash}}
	}

	## PRIVATE
	private variable filename			;# String: Nothing yet ...
	private variable geometry			;# Geometry: Window geometry
	private variable win				;# Widget: Dialog window (widget class Frame)

	private variable main_frame			;# Widget: Main window frame
	private variable canvas_widget			;# Widget: Canvas widget for writing notes
	private variable title_bar			;# Widget: Window title bar
	private variable title_label			;# Widget: Label containg text "Scribble notepad"
	private variable close_button			;# Widget: Close button
	private variable coll_exp_but			;# Widget: Shade button
	private variable minim_flag		0	;# Bool: Shaded or not
	private variable allow_raise_win	1	;# Bool: Allows to use command "raise" to force window visibility
	private variable popup_menu_created	0	;# Bool: Canvas widget popup menu has been created
	private variable menu				;# Widget: Popup menu for he canvas widget

	private variable drawing_mode	P		;# Char: Current drawing mode
	private variable selected_color	black		;# Color: Selected drawing color
	private variable loaded_image	{}		;# Image: Image to insert (image object not filename)
	private variable text_to_write	{}		;# String: Text to insert

	private variable click_X			;# Int: Auxiliary variable for storing last position
	private variable click_Y			;# Int: Auxiliary variable for storing last position

	private variable max_X				;# Int: Auxiliary variable for storing max. allowed position
	private variable max_Y				;# Int: Auxiliary variable for storing max. allowed position

	private variable mode_pen_but			;# Widget: Button "Pencil" mode
	private variable mode_line_but			;# Widget: Button "Line" mode
	private variable mode_arrow_but			;# Widget: Button "Arrow" mode
	private variable mode_rectangle_but		;# Widget: Button "Rectangle" mode
	private variable mode_oval_but			;# Widget: Button "Oval" mode
	private variable mode_text_but			;# Widget: Button "Insert text" mode
	private variable mode_clear_but			;# Widget: Button "Eraser" mode
	private variable load_image_but			;# Widget: Button "Import image"
	private variable select_color_but		;# Widget: Button "Select color"
	private variable move_but			;# Widget: Button "Move canvas" mode
	private variable flag_modified		0	;# Bool: Flag modified

	## contructor
	 # @parm String _file_name	- (Nothing yet)
	 # @parm List _geometry		- {X Y W H}
	constructor {_file_name _geometry} {
		incr count

		set filename $_file_name
		if {$_geometry == {}} {
			set geometry {50 50 300 300}
		} else {
			set geometry $_geometry
		}

		# Configure specific ttk styles
		ttk::style configure Notes.TButton	\
			-padding 0			\
			-background $bgcolor
		ttk::style configure Notes_Flat.TButton	\
			-background $bgcolor		\
			-padding 0			\
			-borderwidth 1			\
			-relief flat
		ttk::style map Notes_Flat.TButton	\
			-relief [list active raised]	\
			-background [list disabled ${::COMMON_BG_COLOR}]

		create_win
	}

	destructor {
		destroy $win
	}

	## Close the window
	 # @return void
	public method close {} {
		if {$flag_modified} {
			if {[tk_messageBox		\
				-type yesno		\
				-icon question		\
				-parent $win		\
				-title [mc "Really close ?"] \
				-message [mc "Do you really want to close your notes ? (There is no save function ...)"]	\
			] != {yes}} then {
				return
			}
		}
		delete object $this
	}

	## Event handler: title bar <Button-1>
	 # @parm Int x - Absolute X coordinate
	 # @parm Int y - Absolute Y coordinate
	 # @return void
	public method title_B1 {x y} {
		set click_X [expr {[winfo x $win] - $x}]
		set click_Y [expr {[winfo y $win] - $y}]

		set max_X [winfo width .]
		set max_Y [winfo height .]
		incr max_X -70
		incr max_Y -70

		focus $title_label
		$title_label	configure -cursor fleur
	}

	## Event handler: title bar <ButtonRelease-1>
	 # @return void
	public method title_B1_release {} {
		$title_label	configure -cursor left_ptr
	}

	## Event handler: title bar <B1-Motion>
	 # @parm Int x - Absolute X coordinate
	 # @parm Int y - Absolute Y coordinate
	 # @return void
	public method title_B1_motion {x y} {
		incr x $click_X
		incr y $click_Y

		if {$x > 0 && $x < $max_X} {
			place $win -x $x
		}
		if {$y > 0 && $y < $max_Y} {
			place $win -y $y
		}
	}

	## Event handler: right bottom corner <Button-1>
	 # @return void
	public method resize_B1 {} {
		set click_X [expr {-[winfo x $win] - [winfo x .]}]
		set click_Y [expr {-[winfo y $win] - [winfo y .]}]

		set max_X [expr {[winfo width .]  + [winfo x .]}]
		set max_Y [expr {[winfo height .] + [winfo y .]}]
	}

	## Event handler: right bottom corner <B1-Motion>
	 # @parm Int x - Absolute X coordinate
	 # @parm Int y - Absolute Y coordinate
	 # @return void
	public method resize_B1_motion {x y} {
		set _x $x
		set _y $y
		incr x $click_X
		incr y $click_Y

		if {$x < 200 || $_x > $max_X} {
			set x [winfo width $win]
		}
		if {$y < 200 || $_y > $max_Y} {
			set y [winfo height $win]
		}
		place $win -width $x -height $y
	}

	## Change drawing mode
	 # @parm Char mode - New mode
	 #	A - Arrow
	 #	C - Eraser
	 #	T - Insert text
	 #	O - Oval
	 #	R - Rectangle
	 #	L - Line
	 #	P - Pencil
	 #	I - Insert image
	 #	M - Move canvas
	 # @return void
	public method change_mode {mode} {
		# Local variables
		set drawing_mode_org $drawing_mode

		# Object variables
		set drawing_mode $mode

		# Bring toolbar buttons to default states
		foreach w [list							\
			$mode_pen_but		$mode_line_but	$mode_arrow_but	\
			$mode_rectangle_but	$mode_oval_but	$mode_text_but	\
			$mode_clear_but		$load_image_but	$move_but	\
		] {
			$w configure -style Notes_Flat.TButton
		}

		# Switch drawing mode
		set w {}
		switch -- $drawing_mode {
			A {	;# Arrow
				$canvas_widget configure -cursor cross
				set w $mode_arrow_but
			}
			C {	;# Eraser
				$canvas_widget configure -cursor left_ptr
				set w $mode_clear_but
			}
			T {	;# Insert text
				if {[prompt_for_text]} {
					$canvas_widget configure -cursor cross
					set w $mode_text_but
				} else {
					if {$drawing_mode_org == {T}} {
						set drawing_mode_org {M}
					}
					change_mode $drawing_mode_org
				}
			}
			O {	;# Draw oval
				$canvas_widget configure -cursor cross
				set w $mode_oval_but
			}
			R {	;# Draw rectangle
				$canvas_widget configure -cursor cross
				set w $mode_rectangle_but
			}
			L {	;# Draw line
				$canvas_widget configure -cursor cross
				set w $mode_line_but
			}
			P {	;# Pencil
				$canvas_widget configure -cursor pencil
				set w $mode_pen_but
			}
			I {	;# Insert image
				$canvas_widget configure -cursor cross
				set w $load_image_but
			}
			M {	;# Move canvas
				$canvas_widget configure -cursor fleur
				set w $move_but
			}
		}

		# Highlight toolbar button belonging to the selected mode
		if {$w != {}} {
			$w configure -style Notes.TButton
		}
	}

	## (Un)Shade window
	 # @return void
	public method collapse_expand {} {
		# Object variables
		set minim_flag [expr {!$minim_flag}]

		# Shade
		if {$minim_flag} {
			set image _1downarrow
			pack forget $main_frame
			place $win -height [expr {[winfo height $win.title_bar] + 4}]
		# Unshade
		} else {
			set image _1uparrow
			pack $main_frame -fill both -expand 1 -padx 2 -pady 2
			place $win -height [expr {[lindex $geometry 3] + 2}]
		}
		$coll_exp_but configure -image ::ICONS::16::$image
	}

	## Create popup menu
	 # @return void
	private method create_popup_menu {} {
		if {$popup_menu_created} {return}
		set popup_menu_created 1

		set menu $canvas_widget.menu
		menuFactory $MENU $menu 0 "$this " 0 {} [namespace current]
	}

	## Popup menu
	 # @parm Int x - Relative X coordinate
	 # @parm Int y - Relative Y coordinate
	 # @parm Int X - Absolute X coordinate
	 # @parm Int Y - Absolute Y coordinate
	 # @return void
	public method popup_menu {x y X Y} {
		create_popup_menu
		set ::Notes::__mode $drawing_mode
		set ::Notes::_menu_x $x
		set ::Notes::_menu_y $y

		tk_popup $menu $X $Y
		focus $title_label
	}

	## Zoom in canvas contents from the specified coordinates
	 # @parm Int x - Relative X coordinate
	 # @parm Int y - Relative Y coordinate
	 # @return void
	public method canvas_zoom_in {x y} {
		$canvas_widget scale all $x $y 1.5 1.5
	}

	## Zoom out canvas contents from the specified coordinates
	 # @parm Int x - Relative X coordinate
	 # @parm Int y - Relative Y coordinate
	 # @return void
	public method canvas_zoom_out {x y} {
		$canvas_widget scale all $x $y 0.75 0.75
	}

	## Zoom in canvas contents (from popup menu)
	 # @return void
	public method canvas_zoom_in_from_pmenu {} {
		canvas_zoom_in $::Notes::_menu_x $::Notes::_menu_y
	}

	## Zoom out canvas contents (from popup menu)
	 # @return void
	public method canvas_zoom_out_from_pmenu {} {
		canvas_zoom_out $::Notes::_menu_x $::Notes::_menu_y
	}

	## Create notepad window
	 # @return void
	private method create_win {} {
		# Create window frame
		set win [frame .notes$count -bd 1 -relief raised -bg $bgcolor]

		## Create title bar
		 # - Title bar frame
		set title_bar [frame $win.title_bar -bg $bgcolor]
		set title_label [label $title_bar.text	\
			-bg $bgcolor -compound left	\
			-text [mc "Scribble notepad"]	\
			-image ::ICONS::16::pencil	\
			-pady 0				\
		]
		 # - Button "Close"
		set close_button [ttk::button $title_bar.close_but	\
			-style Notes_Flat.TButton			\
			-command "$this close"				\
			-image ::ICONS::16::button_cancel		\
			-takefocus 0					\
		]
		DynamicHelp::add $title_bar.close_but -text [mc "Close"]
		setStatusTip -widget $close_button -text [mc "Close"]
		 # - Button "Shade"
		set coll_exp_but [ttk::button $title_bar.col_exp_but	\
			-style Notes_Flat.TButton			\
			-command "$this collapse_expand"		\
			-image ::ICONS::16::_1uparrow			\
			-takefocus 0					\
		]
		DynamicHelp::add $title_bar.col_exp_but -text [mc "Shade"]
		setStatusTip -widget $coll_exp_but -text [mc "Shade"]
		 # Pack buttons
		pack $coll_exp_but -padx 5 -side left -pady 0 -ipady 0
		pack $title_label -side left -fill x -pady 0 -ipady 0 -expand 1
		pack $close_button -side right -pady 0 -ipady 0 -padx 3
		 # Set title bar event bindings
		bind $title_label <Double-1> "$this collapse_expand"
		bind $title_label <Button-1> "$this title_B1 %X %Y"
		bind $title_label <B1-Motion> "$this title_B1_motion %X %Y"
		bind $title_label <ButtonRelease-1>  "$this title_B1_release"

		## Create main frame
		set main_frame  [frame $win.main_frame -bg $bgcolor2]
		set canvas_widget [canvas $main_frame.canvas	\
			-bg $bgcolor2 -highlightthickness 0	\
			-width 0 -height 0 -bd 0		\
		]
		bind $canvas_widget <Button-1> "$this canvas_B1 %x %y"
		bind $canvas_widget <B1-Motion> "$this canvas_B1_motion %x %y"
		bind $canvas_widget <Motion> "$this canvas_motion %x %y"
		bind $canvas_widget <ButtonRelease-1> "$this canvas_B1_release %x %y"
		bind $canvas_widget <ButtonRelease-3> "$this popup_menu %x %y %X %Y"
		bind $canvas_widget <Leave> "$this canvas_leave"
		bind $canvas_widget <Enter> "$this canvas_enter %x %y"

		bind $canvas_widget <Button-4> "$this canvas_zoom_in %x %y"
		bind $canvas_widget <Button-5> "$this canvas_zoom_out %x %y"

		## Create bottom frame
		 # Create the frame
		set bottom_frame [frame $main_frame.bottom_frame -bg $bgcolor]
		 # - Resizing corner
		pack [label $bottom_frame.resize	\
			-bg $bgcolor -cursor lr_angle	\
			-image ::ICONS::16::corner	\
		] -side right
		 # - Set event bindings for the resizing corner
		bind $bottom_frame.resize <Button-1> "$this resize_B1"
		bind $bottom_frame.resize <B1-Motion> "$this resize_B1_motion %X %Y"
		 # - Button "Pencil"
		set mode_pen_but [ttk::button $bottom_frame.mode_pen_but	\
			-command "$this change_mode P"				\
			-image ::ICONS::16::pencil				\
		]
		DynamicHelp::add $bottom_frame.mode_pen_but -text [mc "Pencil"]
		setStatusTip -widget $mode_pen_but -text [mc "Pencil"]
		pack $mode_pen_but -side left -ipady 0
		 # - Button "Line"
		set mode_line_but [ttk::button $bottom_frame.mode_line_but	\
			-command "$this change_mode L"				\
			-image ::ICONS::16::line				\
		]
		DynamicHelp::add $bottom_frame.mode_line_but -text [mc "Line"]
		setStatusTip -widget $mode_line_but -text [mc "Draw lines"]
		pack $mode_line_but -side left -ipady 0
		 # - Button "Arrow"
		set mode_arrow_but [ttk::button $bottom_frame.mode_arrow_but	\
			-command "$this change_mode A"				\
			-image ::ICONS::16::arr					\
		]
		DynamicHelp::add $bottom_frame.mode_arrow_but -text [mc "Arrow"]
		setStatusTip -widget $mode_arrow_but -text [mc "Draw arrows"]
		pack $mode_arrow_but -side left -ipady 0
		 # - Button "Retangle"
		set mode_rectangle_but [ttk::button $bottom_frame.mode_rectangle_but	\
			-command "$this change_mode R"					\
			-image ::ICONS::16::grid1					\
		]
		DynamicHelp::add $bottom_frame.mode_rectangle_but -text [mc "Retangle"]
		setStatusTip -widget $mode_rectangle_but -text [mc "Draw rectangles"]
		pack $mode_rectangle_but -side left -ipady 0
		 # - Button "Oval"
		set mode_oval_but [ttk::button $bottom_frame.mode_oval_but	\
			-command "$this change_mode O"				\
			-image ::ICONS::16::oval				\
		]
		DynamicHelp::add $bottom_frame.mode_oval_but -text [mc "Oval"]
		setStatusTip -widget $mode_oval_but -text [mc "Draw ovals"]
		pack $mode_oval_but -side left -ipady 0
		 # - Button "Insert text"
		set mode_text_but [ttk::button $bottom_frame.mode_text_but	\
			-command "$this change_mode T"				\
			-image ::ICONS::16::editclear				\
		]
		DynamicHelp::add $bottom_frame.mode_text_but -text [mc "Insert text"]
		setStatusTip -widget $mode_text_but -text [mc "Insert text"]
		pack $mode_text_but -side left -ipady 0
		 # - Button "Move"
		set move_but [ttk::button $bottom_frame.move_but		\
			-command "$this change_mode M"				\
			-image ::ICONS::16::mouse				\
		]
		DynamicHelp::add $bottom_frame.move_but -text [mc "Move"]
		setStatusTip -widget $move_but -text [mc "Move"]
		pack $move_but -side left -ipady 0
		 # - Button "Eraser"
		set mode_clear_but [ttk::button $bottom_frame.mode_clear_but	\
			-command "$this change_mode C"				\
			-image ::ICONS::16::eraser				\
		]
		DynamicHelp::add $bottom_frame.mode_clear_but -text [mc "Eraser"]
		setStatusTip -widget $mode_clear_but -text [mc "Eraser"]
		pack $mode_clear_but -side left -ipady 0
		 # - Button "Select color"
		set select_color_but [button $bottom_frame.select_color_but	\
			-command "$this select_color"		\
			-bd 1 -relief raised -overrelief raised	\
			-activebackground $selected_color	\
			-bg $selected_color -pady 0 -width 2	\
		]
		DynamicHelp::add $bottom_frame.select_color_but -text [mc "Select color"]
		setStatusTip -widget $select_color_but -text [mc "Select color"]
		pack $select_color_but -side right -ipady 0 -pady 0 -padx 8
		 # - Button "Insert image"
		set load_image_but [ttk::button $bottom_frame.load_image_but	\
			-command "$this load_image"				\
			-image ::ICONS::16::fileimport				\
		]
		DynamicHelp::add $bottom_frame.load_image_but -text [mc "Insert image"]
		setStatusTip -widget $load_image_but -text [mc "Insert image"]
		pack $load_image_but -side right -ipady 0
		 # - Button "Clear all"
		set clear_all_but [ttk::button $bottom_frame.clear_all_but	\
			-command "$this canvas_clear_all"		\
			-image ::ICONS::16::emptytrash			\
		]
		DynamicHelp::add $bottom_frame.clear_all_but -text [mc "Clear all"]
		setStatusTip -widget $clear_all_but -text [mc "Clear all"]
		pack $clear_all_but -side right -ipady 0
		 # - Separator
		pack [ttk::separator $bottom_frame.sep0	\
			-orient vertical		\
		] -fill y -padx 5 -side right
		 # Restore default states of buttons on the bottom bar
		foreach w [list							\
			$mode_pen_but		$mode_line_but	$mode_arrow_but	\
			$mode_rectangle_but	$mode_oval_but	$mode_text_but	\
			$mode_clear_but		$load_image_but	$clear_all_but	\
			$move_but						\
		] {
			$w configure -style Notes_Flat.TButton
		}

		# Pack all components of the window
		pack $title_bar -fill x
		pack $canvas_widget -fill both -expand 1
		pack $bottom_frame -fill x -side bottom
		pack $main_frame -fill both -expand 1 -padx 2 -pady 2

		# Set default drawing mode
		change_mode P

		# Show the window
		bind $win <Visibility> "$this raise_win"
		place $win				\
			-x [lindex $geometry 0]		\
			-y [lindex $geometry 1]		\
			-width [lindex $geometry 2]	\
			-height [lindex $geometry 3]	\
			-anchor nw
		raise $win
	}

	## Insure window visibility
	 # @return void
	public method raise_win {} {
		if {!$allow_raise_win} {return}
		set allow_raise_win 0
		after 1000 "catch {$this set_allow_raise_win}"
		raise $win
	}

	## @see raise_win
	 # @return void
	public method set_allow_raise_win {} {
		set allow_raise_win 1
	}

	## Prompt user for text to insert to the canvas
	 # @return void
	private method prompt_for_text {} {
		set ::Notes::text_prompt_text {}
		set dialog [toplevel .notes_pd -bg ${::COMMON_BG_COLOR}]

		## Create top frame
		set frame [frame $dialog.frm]
		 # - Label "Text"
		pack [label $frame.lbl		\
			-text [mc "Text:"]	\
		] -side left
		 # - EntryBox
		set entry [ttk::entry $frame.text_entry		\
			-textvariable ::Notes::text_prompt_text	\
			-width 30				\
		]
		 # Pack them
		pack $entry -side left -fill x -expand 1
		pack $frame -padx 5 -pady 5 -fill x -expand 1
		 # Set events bindings
		bind $entry <Return> "
			grab release $dialog
			destroy $dialog
		"
		bind $entry <Escape> "
			set ::Notes::text_prompt_text {}
			grab release $dialog
			destroy $dialog
		"

		## Create bottom frame
		set frame [frame $dialog.frm_b]
		 # - Button "Cancel"
		pack [ttk::button $dialog.cancel_button		\
			-compound left				\
			-image ::ICONS::16::button_cancel	\
			-text [mc "Cancel"]			\
			-command "
				set ::Notes::text_prompt_text {}
				grab release $dialog
				destroy $dialog
			"	\
		] -side right
		 # - Button "Ok"
		pack [ttk::button $dialog.ok_button	\
			-compound left		\
			-image ::ICONS::16::ok	\
			-text [mc "Ok"]		\
			-command "
				grab release $dialog
				destroy $dialog
			"	\
		] -side right
		pack $frame -pady 5 -padx 5 -fill x

		wm title $dialog [mc "Enter text"]
		wm transient $dialog .
		wm geometry $dialog =250x70+[expr {[winfo screenwidth $win] / 2 - 250}]+[expr {[winfo screenheight $win] / 2 - 70}]
		update
		focus -force $entry
		grab $dialog
		raise $dialog
		tkwait window $dialog

		set text_to_write ${::Notes::text_prompt_text}
		return [string length $text_to_write]
	}

	## Event handler: canvas <Enter>
	 # @parm Int x - Relative X coordinate
	 # @parm Int y - Relative Y coordinate
	 # @return void
	public method canvas_enter {x y} {
		switch -- $drawing_mode {
			T {	;# Insert text
				$canvas_widget create text $x $y -text $text_to_write -anchor w -tags incomplete -font $canvas_text_font -fill $selected_color
			}
			I {	;# Import image
				$canvas_widget create image $x $y -image $loaded_image -tags incomplete
			}
		}
	}

	## Event handler: canvas <Button-1>
	 # @parm Int x - Relative X coordinate
	 # @parm Int y - Relative Y coordinate
	 # @return void
	public method canvas_B1 {x y} {
		set click_X $x
		set click_Y $y

		switch -- $drawing_mode {
			C {	;# Eraser
				set flag_modified 1
				$canvas_widget create rectangle			\
					[expr {$x - 10}] [expr {$y - 10}]	\
					[expr {$x + 10}] [expr {$y + 10}]	\
					-outline $bgcolor2 -fill $bgcolor2
			}
			T {	;# Insert text
				set flag_modified 1
				$canvas_widget dtag incomplete incomplete
				$canvas_widget create text $x $y -text $text_to_write -anchor w -tags incomplete -font $canvas_text_font -fill $selected_color
			}
			I {	;# Import image
				set flag_modified 1
				$canvas_widget dtag incomplete incomplete
				$canvas_widget create image $x $y -image $loaded_image -tags incomplete
			}
		}

		focus $canvas_widget
	}

	## Event handler: canvas <Motion>
	 # @parm Int x - Relative X coordinate
	 # @parm Int y - Relative Y coordinate
	 # @return void
	public method canvas_motion {x y} {
		switch -- $drawing_mode {
			C {	;# Eraser
				$canvas_widget delete incomplete
				$canvas_widget create rectangle		\
					[expr {$x - 10}] [expr {$y - 10}]	\
					[expr {$x + 10}] [expr {$y + 10}]	\
					-tag incomplete -outline #FF0000
			}
			T {	;# Insert text
				$canvas_widget coords incomplete $x $y
			}
			I {	;# Import image
				$canvas_widget coords incomplete $x $y
			}
		}
	}

	## Event handler: canvas <B1-Motion>
	 # @parm Int x - Relative X coordinate
	 # @parm Int y - Relative Y coordinate
	 # @return void
	public method canvas_B1_motion {x y} {
		$canvas_widget delete incomplete
		switch -- $drawing_mode {
			C {	;# Eraser
				set flag_modified 1
				$canvas_widget create rectangle			\
					[expr {$x - 10}] [expr {$y - 10}]	\
					[expr {$x + 10}] [expr {$y + 10}]	\
					-outline $bgcolor2 -fill $bgcolor2
				$canvas_widget create rectangle			\
					[expr {$x - 10}] [expr {$y - 10}]	\
					[expr {$x + 10}] [expr {$y + 10}]	\
					-tag incomplete -outline #FF0000
			}
			T {	;# Insert text
				if {![llength [$canvas_widget find withtag incomplete]]} {
					$canvas_widget create text $x $y -text $text_to_write -anchor w -tags incomplete -font $canvas_text_font -fill $selected_color
				}
				$canvas_widget coords incomplete $x $y
			}
			O {	;# Draw oval
				$canvas_widget create oval $click_X $click_Y $x $y -tag incomplete -dash {_} -outline $selected_color
			}
			R {	;# Draw rectangle
				$canvas_widget create rectangle $click_X $click_Y $x $y -tag incomplete -dash {_} -outline $selected_color
			}
			L {	;# Draw line
				$canvas_widget create line $click_X $click_Y $x $y -tag incomplete -dash {_} -fill $selected_color
			}
			P {	;# Pencil
				set flag_modified 1
				$canvas_widget create line $click_X $click_Y $x $y -fill $selected_color
				set click_X $x
				set click_Y $y
			}
			A {	;# Draw arrow
				$canvas_widget create line $click_X $click_Y $x $y -tag incomplete -dash {_} -arrow last -fill $selected_color
			}
			I {	;# Import image
				if {![llength [$canvas_widget find withtag incomplete]]} {
					$canvas_widget create image $x $y -image $loaded_image -tags incomplete
				}
				$canvas_widget coords incomplete $x $y
			}
			M {	;# Move canvas
				$canvas_widget move all [expr {$x - $click_X}] [expr {$y - $click_Y}]

				set click_X $x
				set click_Y $y
			}
		}
	}

	## Event handler: canvas <ButtonRelease-1>
	 # @parm Int x - Relative X coordinate
	 # @parm Int y - Relative Y coordinate
	 # @return void
	public method canvas_B1_release {x y} {
		switch -- $drawing_mode {
			O {	;# Draw oval
				set flag_modified 1
				$canvas_widget itemconfigure incomplete -dash {} -outline $selected_color
				$canvas_widget dtag incomplete incomplete
			}
			R {	;# Draw rectangle
				set flag_modified 1
				$canvas_widget itemconfigure incomplete -dash {} -outline $selected_color
				$canvas_widget dtag incomplete incomplete
			}
			L {	;# Draw line
				set flag_modified 1
				$canvas_widget itemconfigure incomplete -dash {} -fill $selected_color
				$canvas_widget dtag incomplete incomplete
			}
			A {	;# Draw arrow
				set flag_modified 1
				$canvas_widget itemconfigure incomplete -dash {} -fill $selected_color
				$canvas_widget dtag incomplete incomplete
			}
		}
	}

	## Event handler: canvas <Leave>
	 # @return void
	public method canvas_leave {} {
		$canvas_widget delete incomplete
	}

	## Completely clear the canvas
	 # @return void
	public method canvas_clear_all {} {
		if {[tk_messageBox		\
			-parent .		\
			-type yesno		\
			-icon question		\
			-title [mc "Are you sure ?"]	\
			-message [mc "Do you really want to clear this notepad\n(there is no undo action)"]	\
		] != {yes}} {
			return
		}
		$canvas_widget delete all
	}

	## Select drawing color
	 # @return void
	public method select_color {} {
		set color [SelectColor .select_color	\
			-parent .			\
			-color $selected_color		\
			-title [mc "Select color"]	\
		]

		if {$color != {}} {
			set selected_color $color
			$select_color_but configure -bg $color -activebackground $color
		}
	}

	## Select image file to import
	 # @return void
	public method load_image {} {
		catch {delete object ::fsd}

		set directory {}
		catch {
			set directory [$::X::actualProject cget -projectPath]
		}

		KIFSD::FSD ::fsd				\
			-directory $directory			\
			-title [mc "Insert image from file"]	\
			-defaultmask 0 -multiple 0 -filetypes [list			\
				[list [mc "Portable network graphics"]	{*.png}	]	\
				[list [mc "All files"]			{*}	]	\
			]

		::fsd setokcmd "$this load_image_file \[::fsd get\]"
		::fsd activate
	}

	## Import image from file
	 # @parm String file - Full file name
	 # @return void
	public method load_image_file {file} {
		set loaded_image {}
		if {[catch {
			set loaded_image [image create photo -file $file]
		}]} then {
			tk_messageBox			\
				-parent .		\
				-type ok		\
				-icon warning		\
				-title [mc "Unable to read file"]	\
				-message [mc "Unable to read file:\n%s" $file]
			return
		}

		if {$loaded_image != {}} {
			change_mode I
		}
	}
}

# >>> File inclusion guard
}
# <<< File inclusion guard