-
Notifications
You must be signed in to change notification settings - Fork 0
/
view.v
849 lines (744 loc) · 20.8 KB
/
view.v
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
/**********************************************************************
*
* simple Picture Viewer V. 0.9
*
* Copyright (c) 2021 Dario Deledda. All rights reserved.
* Use of this source code is governed by an MIT license
* that can be found in the LICENSE file.
*
* TODO:
* - add an example with shaders
**********************************************************************/
import os
import gg
import gx
import sokol.gfx
import sokol.sgl
import sokol.sapp
import stbi
import szip
import strings
// Help text
const (
help_text_rows = [
"Image Viwer 0.9 help.",
"",
"ESC/q - Quit",
"cur. right - Next image",
"cur. left - Previous image",
"cur. up - Next folder",
"cur. down - Previous folder",
"F - Toggle full screen",
"R - Rotate image of 90 degree",
"I - Toggle the info text",
""
"mouse wheel - next/previous images",
"keep pressed left Mouse button - Pan on the image",
"keep pressed rigth Mouse button - Zoom on the image",
]
)
const (
win_width = 800
win_height = 800
bg_color = gx.black
pi_2 = 3.14159265359 / 2.0
uv = [f32(0),0,1,0,1,1,0,1]! // used for zoom icon during rotations
text_drop_files = "Drop here some images/folder/zip to navigate in the pics"
text_scanning = "Scanning..."
text_loading = "Loading..."
)
enum Viewer_state {
loading
scanning
show
error
}
struct App {
mut:
gg &gg.Context
pip_viewer C.sgl_pipeline
texture C.sg_image
init_flag bool
frame_count int
mouse_x int = -1
mouse_y int = -1
scroll_y int
state Viewer_state = .scanning
// translation
tr_flag bool
tr_x f32 = 0.0
tr_y f32 = 0.0
last_tr_x f32 = 0.0
last_tr_y f32 = 0.0
// scaling
sc_flag bool
scale f32 = 1.0
sc_x f32 = 0.0
sc_y f32 = 0.0
last_sc_x f32 = 0.0
last_sc_y f32 = 0.0
// loaded image
img_w int
img_h int
img_ratio f32 = 1.0
// item list
item_list &Item_list
// Text info and help
show_info_flag bool = true
show_help_flag bool
// zip container
zip &szip.Zip // pointer to the szip structure
zip_index int = -1 // index of the zip contaire item
// memory buffer
mem_buf voidptr // buffer used to load items from files/containers
mem_buf_size int // size of the buffer
// font
font_path string // path to the temp font file
// logo
logo_path string // path of the temp font logo
logo_texture C.sg_image
logo_w int
logo_h int
logo_ratio f32 = 1.0
// string builder
bl strings.Builder = strings.new_builder(512)
}
/******************************************************************************
*
* Texture functions
*
******************************************************************************/
fn create_texture(w int, h int, buf &u8) C.sg_image {
sz := w * h * 4
mut img_desc := C.sg_image_desc{
width: w
height: h
num_mipmaps: 0
min_filter: .linear
mag_filter: .linear
// usage: .dynamic
wrap_u: .clamp_to_edge
wrap_v: .clamp_to_edge
label: &byte(0)
d3d11_texture: 0
}
// comment if .dynamic is enabled
img_desc.data.subimage[0][0] = C.sg_range{
ptr: buf
size: usize(sz)
}
sg_img := C.sg_make_image(&img_desc)
return sg_img
}
fn destroy_texture(sg_img C.sg_image) {
C.sg_destroy_image(sg_img)
}
// Use only if: .dynamic is enabled
fn update_text_texture(sg_img C.sg_image, w int, h int, buf &byte) {
sz := w * h * 4
mut tmp_sbc := C.sg_image_data{}
tmp_sbc.subimage[0][0] = C.sg_range{
ptr: buf
size: usize(sz)
}
C.sg_update_image(sg_img, &tmp_sbc)
}
/******************************************************************************
*
* Memory buffer
*
******************************************************************************/
[inline]
fn (mut app App) resize_buf_if_needed(in_size int) {
// manage the memory buffer
if app.mem_buf_size < in_size {
println("Managing FILE memory buffer, allocated [${in_size}]Bytes")
// free previous buffer if any exist
if app.mem_buf_size > 0 {
unsafe{
free(app.mem_buf)
}
}
// allocate the memory
unsafe {
app.mem_buf = malloc(int(in_size))
app.mem_buf_size = int(in_size)
}
}
}
/******************************************************************************
*
* Loading functions
*
******************************************************************************/
// read_bytes from file in `path` in the memory buffer of app.
[manualfree]
fn (mut app App) read_bytes(path string) bool {
mut fp := os.vfopen(path, 'rb') or {
eprintln("ERROR: Can not open the file [$path].")
return false
}
defer {
C.fclose(fp)
}
cseek := C.fseek(fp, 0, C.SEEK_END)
if cseek != 0 {
eprintln("ERROR: Can not seek in the file [$path].")
return false
}
fsize := C.ftell(fp)
if fsize < 0 {
eprintln("ERROR: File [$path] has size is 0.")
return false
}
C.rewind(fp)
app.resize_buf_if_needed(int(fsize))
nr_read_elements := int(C.fread(app.mem_buf, fsize, 1, fp))
if nr_read_elements == 0 && fsize > 0 {
eprintln("ERROR: Can not read the file [$path] in the memory buffer.")
return false
}
return true
}
// read a file as []byte
pub fn read_bytes_from_file(file_path string) []byte {
mut buffer := []byte{}
buffer = os.read_bytes(file_path) or {
eprintln('ERROR: Texure file: [$file_path] NOT FOUND.')
exit(0)
}
return buffer
}
fn (mut app App) load_texture_from_buffer(buf voidptr, buf_len int) (C.sg_image, int, int) {
// load image
stbi.set_flip_vertically_on_load(true)
img := stbi.load_from_memory(buf, buf_len) or {
eprintln('ERROR: Can not load image from buffer, file: [${app.item_list.lst[app.item_list.item_index]}].')
return app.logo_texture, app.logo_w, app.logo_h
//exit(1)
}
res := create_texture(int(img.width), int(img.height), img.data)
unsafe {
img.free()
}
return res, int(img.width), int(img.height)
}
pub fn (mut app App) load_texture_from_file(file_name string) (C.sg_image, int, int) {
app.read_bytes(file_name)
return app.load_texture_from_buffer(app.mem_buf, app.mem_buf_size)
}
pub fn show_logo(mut app App) {
clear_modifier_params(mut app)
if app.texture != app.logo_texture {
destroy_texture(app.texture)
}
app.texture = app.logo_texture
app.img_w = app.logo_w
app.img_h = app.logo_h
app.img_ratio = f32(app.img_w) / f32(app.img_h)
//app.gg.refresh_ui()
}
pub fn load_image(mut app App) {
if app.item_list.loaded == false || app.init_flag == false {
//show_logo(mut app)
//app.state = .show
return
}
app.state = .loading
clear_modifier_params(mut app)
// destroy the texture, avoid to destroy the logo
if app.texture != app.logo_texture {
destroy_texture(app.texture)
}
// load from .ZIP file
if app.item_list.is_inside_a_container() == true {
app.texture, app.img_w, app.img_h = app.load_texture_from_zip() or {
eprintln('ERROR: Can not load image from .ZIP file [${app.item_list.lst[app.item_list.item_index]}].')
show_logo(mut app)
app.state = .show
return
}
app.img_ratio = f32(app.img_w) / f32(app.img_h)
app.state = .show
//app.gg.refresh_ui()
return
}
// if we are out of the zip, close it
if app.zip_index >= 0 {
app.zip_index = -1
app.zip.close()
}
file_path := app.item_list.get_file_path()
if file_path.len > 0 {
//println("${app.item_list.lst[app.item_list.item_index]} $file_path ${app.item_list.lst.len}")
app.texture, app.img_w, app.img_h = app.load_texture_from_file(file_path)
app.img_ratio = f32(app.img_w) / f32(app.img_h)
//println("texture: [${app.img_w},${app.img_h}] ratio: ${app.img_ratio}")
} else {
app.texture = app.logo_texture
app.img_w = app.logo_w
app.img_h = app.logo_h
app.img_ratio = f32(app.img_w) / f32(app.img_h)
println("texture NOT FOUND: use logo!")
}
app.state = .show
}
/******************************************************************************
*
* Init / Cleanup
*
******************************************************************************/
fn app_init(mut app App) {
app.init_flag = true
// 3d pipeline
mut pipdesc := C.sg_pipeline_desc{}
unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) }
color_state := C.sg_color_state{
blend: C.sg_blend_state{
enabled: true
src_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA)
dst_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA)
}
}
pipdesc.colors[0] = color_state
pipdesc.depth = C.sg_depth_state{
write_enabled: true
compare: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL)
}
pipdesc.cull_mode = .back
app.pip_viewer = sgl.make_pipeline(&pipdesc)
// load logo
app.logo_texture, app.logo_w, app.logo_h = app.load_texture_from_file(app.logo_path)
app.logo_ratio = f32(app.img_w) / f32(app.img_h)
app.img_w = app.logo_w
app.img_h = app.logo_h
app.img_ratio = app.logo_ratio
app.texture = app.logo_texture
println("INIT DONE!")
// init done, load the first image if any
load_image(mut app)
}
fn cleanup(mut app App) {
gfx.shutdown()
// delete temp files
os.rm(app.font_path) or {eprintln("ERROR: Can not delete temp font file.")}
os.rm(app.logo_path) or {eprintln("ERROR: Can not delete temp logo file.")}
println("Cleaning done.")
}
/******************************************************************************
*
* Draw functions
*
******************************************************************************/
[manualfree]
fn frame(mut app App) {
ws := gg.window_size_real_pixels()
if ws.width <= 0 || ws.height <= 0 {
return
}
mut ratio := f32(ws.width) / ws.height
dw := ws.width
dh := ws.height
app.gg.begin()
sgl.defaults()
// set viewport
sgl.viewport(0, 0, dw, dh, true)
// enable our pipeline
sgl.load_pipeline(app.pip_viewer)
sgl.enable_texture()
sgl.texture(app.texture)
// translation
tr_x := app.tr_x / app.img_w
tr_y := -app.tr_y / app.img_h
sgl.push_matrix()
sgl.translate(tr_x, tr_y, 0.0)
// scaling/zoom
sgl.scale(2.0 * app.scale, 2.0 * app.scale, 0.0)
// roation
mut rotation := 0
if app.state == .show && app.item_list.n_item > 0 {
rotation = app.item_list.lst[app.item_list.item_index].rotation
sgl.rotate( pi_2 * f32(rotation) , 0.0, 0.0, -1.0)
}
// draw the image
mut w := f32(0.5)
mut h := f32(0.5)
// for 90 and 270 degree invert w and h
// rotation change image ratio, manage it
if rotation & 1 == 1 {
tmp := w
w = h
h = tmp
h /= app.img_ratio * ratio
} else {
h /= app.img_ratio / ratio
}
// manage image overflow in case of strange scales
if h > 0.5 {
reduction_factor := 0.5 / h
h = h * reduction_factor
w = w * reduction_factor
}
if w > 0.5 {
reduction_factor := 0.5 / w
h = h * reduction_factor
w = w * reduction_factor
}
//println("$w,$h")
// white multiplicator for now
mut c := [byte(255),255,255]!
sgl.begin_quads()
sgl.v2f_t2f_c3b(-w, -h, 0, 0, c[0], c[1], c[2])
sgl.v2f_t2f_c3b( w, -h, 1, 0, c[0], c[1], c[2])
sgl.v2f_t2f_c3b( w, h, 1, 1, c[0], c[1], c[2])
sgl.v2f_t2f_c3b(-w, h, 0, 1, c[0], c[1], c[2])
sgl.end()
// restore all the transformations
sgl.pop_matrix()
// Zoom icon
/*
if app.show_info_flag == true && app.scale > 1 {
mut bw := f32(0.25)
mut bh := f32(0.25 / app.img_ratio)
// manage the rotations
if rotation & 1 == 1 {
bw,bh = bh,bw
}
mut bx := f32(1 - bw)
mut by := f32(1 - bh)
if rotation & 1 == 1 {
bx,by = by,bx
}
bh_old1 := bh
bh *= ratio
by += (bh_old1 - bh)
// draw the zoom icon
sgl.begin_quads()
r := int(u32(rotation) << 1)
sgl.v2f_t2f_c3b(bx , by , uv[(0 + r) & 7] , uv[(1 + r) & 7], c[0], c[1], c[2])
sgl.v2f_t2f_c3b(bx + bw, by , uv[(2 + r) & 7] , uv[(3 + r) & 7], c[0], c[1], c[2])
sgl.v2f_t2f_c3b(bx + bw, by + bh, uv[(4 + r) & 7] , uv[(5 + r) & 7], c[0], c[1], c[2])
sgl.v2f_t2f_c3b(bx , by + bh, uv[(6 + r) & 7] , uv[(7 + r) & 7], c[0], c[1], c[2])
sgl.end()
// draw the zoom rectangle
sgl.disable_texture()
bw_old := bw
bh_old := bh
bw /= app.scale
bh /= app.scale
bx += (bw_old - bw) / 2 - (tr_x / 8) / app.scale
by += (bh_old - bh) / 2 - ((tr_y / 8) / app.scale) * ratio
c = [byte(255),255,0]! // yellow
sgl.begin_line_strip()
sgl.v2f_c3b(bx , by , c[0], c[1], c[2])
sgl.v2f_c3b(bx + bw, by , c[0], c[1], c[2])
sgl.v2f_c3b(bx + bw, by + bh, c[0], c[1], c[2])
sgl.v2f_c3b(bx , by + bh, c[0], c[1], c[2])
sgl.v2f_c3b(bx , by , c[0], c[1], c[2])
sgl.end()
}
*/
sgl.disable_texture()
//
// Draw info text
//
x := 10
y := 10
app.gg.begin()
if app.state in [.scanning, .loading] {
if app.state == .scanning {
draw_text(mut app, text_scanning, x, y, 20)
} else {
draw_text(mut app, text_loading, x, y, 20)
}
} else if app.state == .show {
// print the info text if needed
if app.item_list.n_item > 0 && app.show_info_flag == true {
/*
// waiting for better autofree
num := app.item_list.lst[app.item_list.item_index].n_item
of_num := app.item_list.n_item
x_screen := int(w*2*app.scale*dw)
y_screen := int(h*2*app.scale*dw)
rotation_angle := 90 * rotation
scale_str := "${app.scale:.2}"
text := "${num}/${of_num} [${app.img_w},${app.img_h}]=>[${x_screen},${y_screen}] ${app.item_list.lst[app.item_list.item_index].name} scale: ${scale_str} rotation: ${rotation_angle}"
//text := "${num}/${of_num}"
draw_text(mut app, text, 10, 10, 20)
unsafe{
text.free()
}
*/
// Using string builder to avoid memory leak
num := app.item_list.lst[app.item_list.item_index].n_item
of_num := app.item_list.n_item
x_screen := int(w*2*app.scale*dw)
y_screen := int(h*2*app.scale*dw)
rotation_angle := 90 * rotation
scale_str := "${app.scale:.2}"
app.bl.clear()
app.bl.write_string("${num}/${of_num}")
app.bl.write_string(" [${app.img_w}x${app.img_h}]=>[${x_screen}x${y_screen}]")
app.bl.write_string(" ${app.item_list.lst[app.item_list.item_index].name}")
app.bl.write_string(" scale: ${scale_str} rotation: ${rotation_angle}")
draw_text(mut app, app.bl.str(), 10, 10, 20)
} else {
if app.item_list.n_item <= 0 {
draw_text(mut app, text_drop_files, 10, 10, 20)
}
}
}
//
// Draw Help text
//
if app.show_help_flag == true {
mut txt_y := 30
for r in help_text_rows {
draw_text(mut app, r, 10, txt_y, 20)
txt_y += 20
}
}
app.gg.end()
app.frame_count++
}
// draw readable text
fn draw_text(mut app App, in_txt string, in_x int, in_y int, fnt_sz f32) {
scale := app.gg.scale
font_size := int(fnt_sz * scale)
mut txt_conf_c0 := gx.TextCfg{
color: gx.white //gx.rgb( (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff)
align: .left
size: font_size
}
mut txt_conf_c1 := gx.TextCfg{
color: gx.black //gx.rgb( (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff)
align: .left
size: font_size
}
x := int(in_x * scale)
y := int(in_y * scale)
app.gg.draw_text(x + 2, y + 2, in_txt, txt_conf_c0)
app.gg.draw_text(x, y, in_txt, txt_conf_c1)
}
/******************************************************************************
*
* events management
*
******************************************************************************/
fn clear_modifier_params(mut app App) {
app.scale = 1.0
app.sc_flag = false
app.sc_x = 0
app.sc_y = 0
app.last_sc_x = 0
app.last_sc_y = 0
app.tr_flag = false
app.tr_x = 0
app.tr_y = 0
app.last_tr_x = 0
app.last_tr_y = 0
}
fn my_event_manager(mut ev gg.Event, mut app App) {
// navigation using the mouse wheel
app.scroll_y = int(ev.scroll_y)
if app.scroll_y != 0 {
inc := int(-1 * app.scroll_y/4)
if app.item_list.n_item > 0 {
app.item_list.get_next_item(inc)
load_image(mut app)
}
}
if ev.typ == .mouse_move {
app.mouse_x = int(ev.mouse_x)
app.mouse_y = int(ev.mouse_y)
}
if ev.typ == .touches_began || ev.typ == .touches_moved {
if ev.num_touches > 0 {
touch_point := ev.touches[0]
app.mouse_x = int(touch_point.pos_x)
app.mouse_y = int(touch_point.pos_y)
}
}
// clear all parameters
if ev.typ == .mouse_down && ev.mouse_button == .middle {
clear_modifier_params(mut app)
}
//ws := gg.window_size_real_pixels()
//ratio := f32(ws.width) / ws.height
//dw := ws.width
//dh := ws.height
// --- translate ---
if ev.typ == .mouse_down && ev.mouse_button == .left {
app.tr_flag = true
app.last_tr_x = app.mouse_x
app.last_tr_y = app.mouse_y
}
if ev.typ == .mouse_up && ev.mouse_button == .left && app.tr_flag == true {
app.tr_flag = false
}
if ev.typ == .mouse_move && app.tr_flag == true {
app.tr_x += (app.mouse_x - app.last_tr_x) * 3 * app.gg.scale
app.tr_y += (app.mouse_y - app.last_tr_y) * 3 * app.gg.scale
app.last_tr_x = app.mouse_x
app.last_tr_y = app.mouse_y
//println("Translate: ${app.tr_x} ${app.tr_y}")
}
// --- scaling ---
if ev.typ == .mouse_down && ev.mouse_button == .right && app.sc_flag == false {
app.sc_flag = true
app.last_sc_x = app.mouse_x
app.last_sc_y = app.mouse_y
}
if ev.typ == .mouse_up && ev.mouse_button == .right && app.sc_flag == true {
app.sc_flag = false
}
if ev.typ == .mouse_move && app.sc_flag == true {
app.sc_x = app.mouse_x - app.last_sc_x
app.sc_y = app.mouse_y - app.last_sc_y
app.last_sc_x = app.mouse_x
app.last_sc_y = app.mouse_y
app.scale += f32(app.sc_x / 100 )
if app.scale < 0.1 {
app.scale = 0.1
}
if app.scale > 32 {
app.scale = 32
}
}
if ev.typ == .key_down {
//println(ev.key_code)
// Exit using the ESC key or Q key
if ev.key_code == .escape || ev.key_code == .q {
cleanup(mut app)
exit(0)
}
// Toggle info text OSD
if ev.key_code == .i {
app.show_info_flag = !app.show_info_flag
}
// Toggle help text
if ev.key_code == .h {
app.show_help_flag = !app.show_help_flag
}
// do actions only if there are items in the list
if app.item_list.loaded == true && app.item_list.n_item > 0 {
// show previous image
if ev.key_code == .left {
app.item_list.get_next_item(-1)
load_image(mut app)
}
// show next image
if ev.key_code == .right {
app.item_list.get_next_item(1)
load_image(mut app)
}
// jump to the next container if possible
if ev.key_code == .up {
app.item_list.go_to_next_container(1)
load_image(mut app)
}
// jump to the previous container if possible
if ev.key_code == .down {
app.item_list.go_to_next_container(-1)
load_image(mut app)
}
// rotate the image
if ev.key_code == .r {
app.item_list.rotate(1)
}
// full screen
if ev.key_code == .f {
println("Full screen state: ${sapp.is_fullscreen()}")
sapp.toggle_fullscreen()
}
}
}
// drag&drop
if ev.typ == .files_droped {
app.state = .scanning
// set logo texture during scanning
show_logo(mut app)
num := sapp.get_num_dropped_files()
mut file_list := []string{}
for i in 0..num {
file_list << sapp.get_dropped_file_path(i)
}
println("Scanning: ${file_list}")
app.item_list = &Item_list{}
app.item_list.loaded = false
// load_image(mut app)
// go app.item_list.get_items_list(file_list)
load_and_show(file_list, mut app)
}
}
fn load_and_show(file_list []string, mut app App) {
app.item_list.get_items_list(file_list)
load_image(mut app)
}
/******************************************************************************
*
* Main
*
******************************************************************************/
// is needed for easier diagnostics on windows
[console]
fn main() {
//mut font_path := os.resource_abs_path(os.join_path('../assets/fonts/', 'RobotoMono-Regular.ttf'))
font_name := 'ShareTechMono-Regular.ttf'
font_path := os.join_path(os.temp_dir(), font_name)
println("Temporary path for the font file: [$font_path]")
// if the font doesn't exist create it from the ebedded one
if os.exists(font_path) == false {
println("Write font [$font_name] in temp folder.")
embedded_file := $embed_file('ShareTechMono-Regular.ttf')
os.write_file(font_path, embedded_file.to_string()) or {
eprintln("ERROR: not able to write font file to [$font_path]")
exit(1)
}
}
// logo image
logo_name := 'logo.png'
logo_path := os.join_path(os.temp_dir(), logo_name)
println("Temporary path for the logo: [$logo_path]")
// if the logo doesn't exist create it from the ebedded one
if os.exists(logo_path) == false {
println("Write logo [$logo_name] in temp folder.")
embedded_file := $embed_file('logo.png')
os.write_file(logo_path, embedded_file.to_string()) or {
eprintln("ERROR: not able to write logo file to [$logo_path]")
exit(1)
}
}
// App init
mut app := &App{
gg: 0
// zip fields
zip: 0
item_list: 0
}
app.state = .scanning
app.logo_path = logo_path
app.font_path = font_path
// Scan all the arguments to find images
app.item_list = &Item_list{}
//app.item_list.get_items_list(os.args[1..])
load_and_show(os.args[1..], mut app)
app.gg = gg.new_context(
width: win_width
height: win_height
create_window: true
window_title: 'V Image viewer 0.8'
user_data: app
bg_color: bg_color
frame_fn: frame
init_fn: app_init
cleanup_fn: cleanup
event_fn: my_event_manager
font_path: font_path
enable_dragndrop: true
max_dropped_files: 64
max_dropped_file_path_length: 2048
//ui_mode: true
)
app.gg.run()
}