1import math
2import os
3import random
4
5# from numpy import array, float32
6from fsgs.platform import PlatformHandler
7from arcade.glui.constants import TOP_ITEM_ARROW, TOP_ITEM_LEFT
8from arcade.glui.constants import ROW_NAME, ROW_PLATFORM
9
10from fsbc.util import memoize
11from fsgs.Database import Database
12from fsgs.util.gamenameutil import GameNameUtil
13from arcade.resources import resources, gettext
14from .font import BitmapFont
15from .opengl import gl, fs_emu_blending, fs_emu_texturing
16from .render import Render
17from arcade.glui.state import State
18from arcade.glui.texture import Texture
19from arcade.glui.texturemanager import TextureManager
20from .errordialog import show_exception
21
22LIGHTING = False
23DIRTY_WHILE_NOT_LOADED = True
24
25
26def create_item_menu(name):
27    from arcade.glui.itemmenu import ItemMenu
28
29    return ItemMenu(name)
30
31
32def create_mesh(width, height, upsidedown):
33    hw = width / 2
34    hh = height / 2
35    if LIGHTING:
36        res = 200
37        radius = 0.018
38    else:
39        res = 2
40        radius = 0.0
41    # radius = 0.1
42    mesh = []
43    for y in range(0, res + 1):
44        y = -hh + y * height / res
45        line = []
46        mesh.append(line)
47        for x in range(0, res + 1):
48            x = -hw + x * width / res
49            # d = min(x, y, res- x, res -y) / (res / 2.0)
50            # rx = x * 2.0 / res
51            z = radius
52            nx = 0.0
53            ny = 0.0
54            nz = 1.0
55            # edge = False
56            # using max to account for rounding errors - d cannot be negative
57            d = max(0, hw - abs(x))
58            # print(hw, x, d)
59            if d < radius:
60                d = radius - d
61                # d = radius - 1.0 - x
62                # print(d, d / radius)
63                a = math.acos(d / radius)
64                # print(a)
65                z = math.sin(a) * radius
66                nx = -d if x < 0 else d
67                nz = z
68                # edge = True
69            # using max to account for rounding errors - d cannot be negative
70            d = max(0, hh - abs(y))
71            if d < radius:
72                d = radius - d
73                # d = radius - 1.0 - x
74                # print(d, d / radius)
75                a = math.acos(d / radius)
76                # print(a)
77                z = min(z, math.sin(a) * radius)
78                ny = -d if y < 0 else d
79                nz = z
80                # edge = True
81            nl = math.sqrt(nx ** 2 + ny ** 2 + nz ** 2)
82            nx /= nl
83            ny /= nl
84            nz /= nl
85            line.append((x, y, z, nx, ny, nz))
86            # if edge:
87            #     line.append((x, y, -z, nx, ny, -nz))
88    return mesh
89
90
91# @memoize
92# def get_vbo_for_cover(width, height):
93#     floats = []
94#     upsidedown=False
95#     mesh = create_mesh(width, height, upsidedown)
96#     hw = width / 2
97#     hh = height / 2
98#     mesh_size = len(mesh)
99#     print(mesh_size)
100#     count = 0
101#     for iy in range(mesh_size - 1):
102#         for ix in range(mesh_size - 1):
103#             def vertex(ix, iy):
104#                 x, y, z, nx, ny, nz = mesh[iy][ix]
105#                 if upsidedown:
106#                     s, t = (x + hw) / width, (y + hh) / height
107#                 else:
108#                     s, t = (x + hw) / width, 1.0 - (y + hh) / height
109#                 floats.extend([s, t, nx, ny, nz, x, y, z])
110#             vertex(ix, iy)
111#             vertex(ix + 1, iy)
112#             vertex(ix + 1, iy + 1)
113#             vertex(ix, iy + 1)
114#             count += 4
115#     # FIXME: specify usage with usage kw arg (specify as "static" data,
116#     # used often)
117#     vbo = VBO(array(floats, dtype=float32))
118#     return vbo, count
119
120
121def render_cover(texture, width, height):
122    if not texture:
123        texture = Texture.missing_cover
124    texture.bind()
125    x = -width / 2.0
126    # y = height / 2.0 - 0.5 - height / 2.0
127    y = -0.5
128    # if reflection:
129
130    gl.glBegin(gl.GL_QUADS)
131    gl.glColor3f(0.33, 0.33, 0.33)
132    gl.glTexCoord2f(0.0, 1.0)
133    gl.glVertex2f(x, y)
134    gl.glTexCoord2f(1.0, 1.0)
135    gl.glVertex2f(x + width, y)
136    gl.glTexCoord2f(1.0, 0.0)
137    gl.glVertex2f(x + width, y - height)
138    gl.glTexCoord2f(0.0, 0.0)
139    gl.glVertex2f(x, y - height)
140    gl.glEnd()
141
142    # else:
143    gl.glBegin(gl.GL_QUADS)
144    gl.glColor3f(1.0, 1.0, 1.0)
145    gl.glTexCoord2f(0.0, 1.0)
146    gl.glVertex2f(x, y)
147    gl.glTexCoord2f(1.0, 1.0)
148    gl.glVertex2f(x + width, y)
149    gl.glTexCoord2f(1.0, 0.0)
150    gl.glVertex2f(x + width, y + height)
151    gl.glTexCoord2f(0.0, 0.0)
152    gl.glVertex2f(x, y + height)
153    gl.glEnd()
154
155    # glPushMatrix()
156    # glTranslatef(0.0, height / 2.0 - 0.5, 0.0)
157    # vbo, count = get_vbo_for_cover(width, height)
158    # vbo.bind()
159    # glInterleavedArrays(GL_T2F_N3F_V3F, 0, None)
160    # if reflection:
161    #     glScalef(1.0, -1.0, 1.0)
162    #     glTranslatef(0.0, height, 0.0)
163    #     if LIGHTING:
164    #         # No point in drawing everything
165    #         glDrawArrays(GL_QUADS, 0, count // 4)
166    #     else:
167    #         glDrawArrays(GL_QUADS, 0, count)
168    # else:
169    #     glDrawArrays(GL_QUADS, 0, count)
170    # vbo.unbind()
171    # glPopMatrix()
172
173
174class MenuItem(object):
175    def __init__(self, title=""):
176        self.ratio = 0.75
177        self.title = title
178        self.supertitle = ""
179        self.subtitle = ""
180        self.path_title = title
181        self.path_title_active = ""
182        # x, y, w and h are used by top menu items
183        self.x = 0
184        self.y = 0
185        self.w = 0
186        self.h = 0
187        self.enabled = True
188
189    def activate(self, menu):
190        print("Activate not overidden")
191
192    @memoize
193    def get_image_files(self):
194        path = self.get_image_path()
195        if path:
196            return [path]
197        return []
198
199    def get_default_texture(self):
200        return Texture.default_item
201
202    def get_texture(self):
203        path = self.get_image_path()
204        if path:
205            try:
206                texture = TextureManager.get().get_texture(path)
207            except KeyError:
208                texture = None
209            if texture:
210                if texture is Texture.default_item:
211                    return Texture.missing_cover
212                return texture
213            else:
214                Render.get().dirty = DIRTY_WHILE_NOT_LOADED
215        return Texture.missing_cover
216        # return self.get_default_texture()
217
218    @memoize
219    def get_image_path(self):
220        name = self.get_resource_name()
221        if name:
222            try:
223                return resources.resource_filename(
224                    os.path.join(u"items", name + u".png")
225                )
226            except Exception:
227                pass
228        return None
229
230    def get_resource_name(self):
231        return None
232
233    def render(
234        self,
235        width,
236        height,
237        border_color=(0.0, 0.0, 0.0, 1.0),
238        inner_border_color=(0.92, 0.92, 0.92),
239        height_offset=0.0,
240        brightness=1.0,
241        ratio=None,
242        area=None,
243    ):
244        render_cover(self.get_texture(), width, height)
245
246    def create_menu_path(self, menu):
247        path = []
248        # while menu:
249        if not menu:
250            return path
251        path.append(menu.selected_item)
252        for p in reversed(menu.parents):
253            # path.insert(0, menu.selected_item)
254            path.insert(0, p.selected_item)
255            # menu = menu.parent_menu
256        print("create_menu_path", path)
257        for p in path:
258            print(p.path_title)
259        return path
260
261    def get_category_filter(self):
262        return None
263
264    def get_game_filter(self):
265        return None
266
267    def generate_category_filters(self, menu_path):
268        for item in menu_path:
269            flt = item.get_category_filter()
270            if flt:
271                yield flt
272
273    def generate_game_filters(self, menu_path):
274        for item in menu_path:
275            flt = item.get_game_filter()
276            if flt:
277                yield flt
278
279    def generate_category_items(self, menu_path):
280        category_filters = list(self.generate_category_filters(menu_path))
281
282        def check(cat):
283            for flt in category_filters:
284                if not flt(cat):
285                    return False
286            return True
287
288        categories = [
289            PlatformMenuItem(),
290            LetterMenuItem(),
291            ShuffleMenuItem(),
292            ListMenuItem(),
293            # YearMenuItem(),
294            # KeywordMenuItem(),
295        ]
296        if len(menu_path) == 0:
297            categories.insert(0, AllMenuItem())
298        return [item for item in categories if check(item)]
299
300    def generate_game_items(self, menu_path):
301        args = []
302        clause = []
303        list_uuid = None
304        for item in menu_path:
305            c, a = item.get_filter_clause()
306            if c:
307                clause.append(c)
308                args.extend(a)
309            if item.get_filter_list_uuid():
310                list_uuid = item.get_filter_list_uuid()
311        # clause = " ".join(clause)
312
313        filters = list(self.generate_game_filters(menu_path))
314        print("filters for", menu_path, "-", filters)
315        return self.create_game_items(clause, args, filters, list_uuid)
316
317    @classmethod
318    def create_game_items(cls, words, args=None, filters=None, list_uuid=None):
319        if filters is None:
320            filters = []
321        search = " ".join(words)
322        item_list = []
323        local_game_database = Database.instance()
324        for game in local_game_database.find_games_new(
325            search=search, database_only=True, list_uuid=list_uuid
326        ):
327            item = GameItem(game)
328            for filter in filters:
329                pass
330                # if not filter(game):
331                #     break
332            else:
333                item_list.append(item)
334        return item_list
335
336    def get_filter_clause(self):
337        return "", []
338
339    def get_filter_list_uuid(self):
340        return None
341
342    def update_size_left(self):
343        self.update_size(self.get_top_left_text())
344
345    def update_size_right(self):
346        self.update_size(self.get_top_right_text())
347
348    def update_size(self, text):
349        # w, h = Render.get().measure_text(text, Font.main_path_font)
350        w, h = BitmapFont.title_font.measure(text)
351        self.w = w + 20 + 20
352
353    def get_top_left_text(self):
354        return self.path_title_active.upper() or self.path_title.upper()
355
356    def get_top_right_text(self):
357        return self.title.upper()
358
359    def render_top_background(
360        self,
361        selected,
362        style=TOP_ITEM_ARROW,
363        mouse_state=False,
364        mouse_pressed_state=False,
365    ):
366        x, y, w, h = self.x, self.y, self.w, self.h
367        z = -0.01 - 0.01 * x / 1920
368        selected = selected or mouse_state
369        if selected:
370            fs_emu_texturing(True)
371            fs_emu_blending(True)
372            if mouse_pressed_state:
373                alpha = 0.75
374            else:
375                alpha = 1.0
376            Texture.top_item_background.render(x, y, w, h, z, opacity=alpha)
377            # fs_emu_texturing(False)
378            # fs_emu_blending(False)
379            # gl.glBegin(gl.GL_QUADS)
380            # gl.glColor3f(0.00, 0x99 / 0xff, 0xcc / 0xff)
381            # gl.glVertex3f(x + 4, y + 4, z)
382            # gl.glVertex3f(x + w - 4, y + 4, z)
383            # gl.glVertex3f(x + w - 4, y + h - 4, z)
384            # gl.glVertex3f(x + 4, y + h - 4, z)
385            # gl.glEnd()
386
387            # fs_emu_blending(True)
388            # glColor3f(1.0, 1.0, 1.0)
389            #
390            # #z = -0.01
391            #
392            # if style == TOP_ITEM_LEFT:
393            #     if selected:
394            #         texture = Texture.top_item_left_selected
395            #     else:
396            #         texture = Texture.top_item_left
397            #     texture.bind()
398            #     tw, th = texture.size
399            #     w = 60
400            #
401            #     glBegin(GL_QUADS)
402            #     glTexCoord2f(0.0, 1.0)
403            #     glVertex3f(x, y, z)
404            #     glTexCoord2f(1.0, 1.0)
405            #     glVertex3f(x + w, y, z)
406            #     glTexCoord2f(1.0, 0.0)
407            #     glVertex3f(x + w, y + h, z)
408            #     glTexCoord2f(0.0, 0.0)
409            #     glVertex3f(x, y + h, z)
410            #     glEnd()
411            #     x += 60
412            #
413            # w = self.w - 60
414            #
415            # if selected:
416            #     texture = Texture.top_item_selected
417            #     x = x - 60
418            #     w = w + 60
419            # else:
420            #     texture = Texture.top_item
421            # texture.bind()
422            # tw, th = texture.size
423            # glBegin(GL_QUADS)
424            # glTexCoord2f(0.0, 1.0)
425            # glVertex3f(x, y, z)
426            # glTexCoord2f(1.0, 1.0)
427            # glVertex3f(x + w, y, z)
428            # glTexCoord2f(1.0, 0.0)
429            # glVertex3f(x + w, y + h, z)
430            # glTexCoord2f(0.0, 0.0)
431            # glVertex3f(x, y + h, z)
432            # glEnd()
433            #
434            # if style == TOP_ITEM_ARROW or style == TOP_ITEM_RIGHT:
435            #     if style == TOP_ITEM_ARROW:
436            #         if selected:
437            #             texture = Texture.top_item_arrow_selected
438            #         else:
439            #             texture = Texture.top_item_arrow
440            #         texture.bind()
441            #         tw, th = texture.size
442            #     else:
443            #         Texture.top_item_right.bind()
444            #         tw, th = Texture.top_item_right.size
445            #     x = x + w
446            #     w = 60
447            #
448            #     glBegin(GL_QUADS)
449            #     glTexCoord2f(0.0, 1.0)
450            #     glVertex3f(x, y, z)
451            #     glTexCoord2f(1.0, 1.0)
452            #     glVertex3f(x + w, y, z)
453            #     glTexCoord2f(1.0, 0.0)
454            #     glVertex3f(x + w, y + h, z)
455            #     glTexCoord2f(0.0, 0.0)
456            #     glVertex3f(x, y + h, z)
457            #     glEnd()
458            #
459            # fs_emu_blending(False)
460
461    def render_top_left(self, selected=False):
462        state = State.get()
463        mouse_state = state.mouse_item == self
464        mouse_pressed_state = mouse_state and state.mouse_press_item == self
465        self.render_top_background(
466            selected,
467            style=TOP_ITEM_LEFT,
468            mouse_state=mouse_state,
469            mouse_pressed_state=mouse_pressed_state,
470        )
471        text = self.get_top_left_text()
472        self.render_top(text, selected)
473
474    def render_top_right(self, selected=False):
475        state = State.get()
476        mouse_state = state.mouse_item == self
477        mouse_pressed_state = mouse_state and state.mouse_press_item == self
478        self.render_top_background(
479            selected,
480            style=TOP_ITEM_LEFT,
481            mouse_state=mouse_state,
482            mouse_pressed_state=mouse_pressed_state,
483        )
484        self.render_top(self.get_top_right_text(), selected)
485
486    def render_top(self, text="", selected=False, right_align=False):
487        if right_align:
488            tw, th = BitmapFont.title_font.measure(text)
489            x = self.x + self.w - 20 - tw
490        else:
491            x = self.x + 20
492            # if selected:
493            #     color = (0.0, 0.0, 0.0)
494            # else:
495            #     color = (0.85, 0.85, 0.85)
496            # tw, th = Render.get().text(text, Font.main_path_font,
497            #         x, self.y + 30, h=TOP_HEIGHT_VISIBLE, color=color)
498        BitmapFont.title_font.render(text, x, self.y + 14)
499        # print(BitmappedFont.title_font.h)
500
501    def get_screen_texture(self, n):
502        return Texture.missing_screenshot
503        # return None
504
505
506class AutoExpandItem(MenuItem):
507    def activate(self, menu):
508        new_menu = create_item_menu(self.title)
509        menu_path = self.create_menu_path(menu)
510        new_menu.update_path(menu_path)
511        want_selected = len(new_menu)
512        for item in self.generate_game_items(menu_path):
513            new_menu.append(item)
514        if len(new_menu) > want_selected:
515            new_menu.set_selected_index(want_selected, immediate=True)
516        new_menu.add_add_item()
517        return new_menu
518
519
520class DummyItem(MenuItem):
521    def __init__(self, title):
522        MenuItem.__init__(self)
523        self.title = title
524
525
526class NoItem(MenuItem):
527    def __init__(self, title="N/A"):
528        MenuItem.__init__(self)
529        self.title = title
530
531    def get_default_texture(self):
532        return Texture.missing_cover
533
534    def activate(self, menu):
535        return
536
537
538class NoLastPlayedItem(MenuItem):
539    def __init__(self):
540        MenuItem.__init__(self)
541        self.title = gettext("No Last Played")
542
543
544class ListMenuItem(MenuItem):
545    def __init__(self):
546        MenuItem.__init__(self)
547        self.title = gettext("List")
548        self.path_title_active = "Choose List"
549
550    def get_resource_name(self):
551        return "list"
552
553    def activate(self, menu):
554        print("ListMenuItem.activate")
555        new_menu = create_item_menu(gettext("Select List"))
556        menu_path = self.create_menu_path(menu)
557        new_menu.update_path(menu_path)
558        # Database.cursor.execute("SELECT DISTINCT platform FROM Game "
559        #         "ORDER BY platform")
560        # items = []
561        # for row in Database.cursor:
562        #     item = PlatformItem(row[0])
563        #     items.append((item.sort_title, item))
564        # for sort_title, item in sorted(items):
565        #    new_menu.append(item)
566
567        for title, path in ListItem.get_game_lists():
568            item = ListItem(title, path)
569            new_menu.append(item)
570        return new_menu
571
572
573class ListItem(AutoExpandItem):
574    def __init__(self, title, path):
575        AutoExpandItem.__init__(self)
576        self.list_path = path
577        self.title = title
578        # self.platform = platform
579        self.path_title = title
580        self.subtitle = ""
581        self.sort_title = self.title
582        # self.game_filter_set = set()
583        self._list = None
584
585    @classmethod
586    def get_game_lists(cls):
587        result = []
588        local_game_database = Database.instance()
589        for list_uuid, list_name in local_game_database.get_game_lists():
590            result.append((list_name, list_uuid))
591        return result
592
593    @classmethod
594    def get_favorites_uuid(cls):
595        for list_name, list_uuid in cls.get_game_lists():
596            # FIXME: Should use some common function to determine this
597            if list_name == "Favorites":
598                return list_uuid
599        raise LookupError("No favorites list")
600
601    def get_category_filter(self):
602        def category_filter(category):
603            if category.__class__ == ListMenuItem:
604                return False
605            return True
606
607        return category_filter
608
609    def get_filter_list_uuid(self):
610        return self.list_path
611
612        # @memoize
613
614    # def get_list_contents(self):
615    #     if self._list is None:
616    #         self._list = set()
617    #         local_game_database = Database.instance()
618    #         local_game_database.get
619    #     return self._list
620
621    # def get_game_filter(self):
622    #
623    #     def game_filter(game):
624    #         game_uuids = set()
625    #         if game.uuid in game_uuids:
626    #             return True
627    #         return False
628    #
629    #     return game_filter
630
631    # def get_filter_clause(self):
632    #     # FIXME: NUMBERS
633    #     return "AND platform = ?", [self._platform]
634    #     print(name)
635
636
637class PlatformMenuItem(MenuItem):
638    def __init__(self):
639        MenuItem.__init__(self)
640        self.title = gettext("Platform")
641        self.path_title_active = "Choose Platform"
642
643    def get_resource_name(self):
644        return "platform"
645
646    def activate(self, menu):
647        print("PlatformMenuItem.activate")
648        new_menu = create_item_menu(gettext("Select Platform"))
649        menu_path = self.create_menu_path(menu)
650        new_menu.update_path(menu_path)
651        with Database.instance() as database:
652            cursor = database.cursor()
653            cursor.execute(
654                "SELECT DISTINCT platform FROM game WHERE have >= 3 "
655                "ORDER BY platform"
656            )
657            items = []
658            for row in cursor:
659                if not row[0]:
660                    continue
661                item = PlatformItem(row[0])
662                items.append((item.sort_title, item))
663            for sort_title, item in sorted(items):
664                new_menu.append(item)
665        return new_menu
666
667
668class PlatformItem(AutoExpandItem):
669    def __init__(self, platform):
670        AutoExpandItem.__init__(self)
671        self._platform = platform
672        # using self.platform for "description"
673
674        # self.sort_title = ""
675        # try:
676        #    self.title, self.subtitle, self.sort_title = {
677        #        "Amiga": (
678        #            "Amiga",
679        #            "Commodore Amiga",
680        #            "Commodore 2"),
681        #        "amstrad-cpc": (
682        #            "Amstrad CPC",
683        #            "Color Personal Computer",
684        #            ""),
685        #        "apple-II": (
686        #            "Apple II",
687        #            "II/Plus/e/c",
688        #            ""),
689        #        "arcade": (
690        #            "Arcade Video Games",
691        #            "Multiple Arcade Machines",
692        #            ""),
693        #        "atari-2600": (
694        #            "Atari 2600",
695        #            "Video Computer System",
696        #            "Atari 1"),
697        #        "atari-8-bit": (
698        #            "Atari 8-Bit",
699        #            "Atari 400/800/XL/XE",
700        #            "Atari 2"),
701        #        "atari-5200": (
702        #            "Atari 5200",
703        #            "Atari 5200 SuperSystem",
704        #            "Atari 3"),
705        #        "atari-7800": (
706        #            "Atari 7800",
707        #            "Atari 7800 ProSystem",
708        #            "Atari 4"),
709        #        "atari-st": (
710        #            "Atari ST",
711        #            "Atari ST/STE",
712        #            "Atari 5"),
713        #        "bbc-micro": (
714        #            "BBC Micro",
715        #            "Acorn BCC Micro",
716        #            ""),
717        #        "commodore-64": (
718        #            "Commodore 64",
719        #            "",
720        #            "Commodore 1"),
721        #        "game-boy": (
722        #            "Game Boy",
723        #            "",
724        #            "Nintendo 2"),
725        #        "game-boy-color": (
726        #            "Game Boy Color",
727        #            "",
728        #            "Nintendo 5"),
729        #        "game-boy-advance": (
730        #            "Game Boy Advance",
731        #            "",
732        #            "Nintendo 6"),
733        #        "game-cube": (
734        #            "GameCube",
735        #            "Nintendo GameCube",
736        #            "Nintendo 7"),
737        #        "game-gear": (
738        #            "Game Gear",
739        #            "Sega Game Gear",
740        #            "Sega 3"),
741        #        "lynx": (
742        #            "Atari Lynx",
743        #            "",
744        #            "Atari 6"),
745        #        "nintendo": (
746        #            "Nintendo",
747        #            "",
748        #            "Nintendo 1"),
749        #        "nintendo-64": (
750        #            "Nintendo 64",
751        #            "",
752        #            "Nintendo 4"),
753        #        "DOS": (
754        #            "DOS",
755        #            "IBM PC Compatible",
756        #            "PC 1"),
757        #        "master-system": (
758        #            "Master System",
759        #            "Sega Master System / Mark III",
760        #            "Sega 1"),
761        #        "mega-drive": (
762        #            "Mega Drive",
763        #            "Sega Mega Drive / Genesis",
764        #            "Sega 2"),
765        #        "playstation": (
766        #            "PlayStation",
767        #            "Sony PlayStation",
768        #            ""),
769        #        "playstation-2": (
770        #            "PlayStation 2",
771        #            "Sony PlayStation 2",
772        #            ""),
773        #        "super-nintendo": (
774        #            "Super Nintendo",
775        #            "Entertainment System",
776        #            "Nintendo 3"),
777        #        "turbografx-16": (
778        #            "TurboGrafx-16",
779        #            "Entertainment SuperSystem",
780        #            ""),
781        #        "wii": (
782        #            "Wii",
783        #            "Nintendo Wii",
784        #            "Nintendo 8"),
785        #        "windows": (
786        #            "Windows",
787        #            "IBM PC Compatible",
788        #            "PC 2"),
789        #        "zx-spectrum": (
790        #            "ZX Spectrum",
791        #            "Sinclair ZX Spectrum",
792        #            ""),
793        #    }[platform]
794        # except KeyError:
795        #    self.title = platform
796        self.platform = platform
797        self.path_title = platform
798
799        self.title = PlatformHandler.get_platform_name(platform)
800        self.path_title = self.title
801
802        # self.title = ""
803        # self.title = "CHOOSE PLATFORM: " + self.title
804        # self.subtitle = ""
805        self.subtitle = "CHOOSE PLATFORM"
806
807        # if not self.sort_title:
808        #     self.sort_title = self.title
809
810        # FIXME: for now, test using just title as sort title
811        self.sort_title = self.title
812
813    def get_category_filter(self):
814        def category_filter(category):
815            if category.__class__ == PlatformMenuItem:
816                return False
817            return True
818
819        return category_filter
820
821    # def get_game_filter(self):
822    #     def game_filter(game_info):
823    #         if game_info.platform == self._platform:
824    #             return True
825    #         return False
826    #     return game_filter
827
828    @memoize
829    def get_resource_name(self):
830        name = ""
831        for c in self._platform.lower():
832            if c in "abcdefghijklmnopqrstuvwxyz0123456789":
833                name = name + c
834        return name
835
836    def get_filter_clause(self):
837        return "s:{0}".format(self._platform), []
838
839
840class AllMenuItem(AutoExpandItem):
841    def __init__(self):
842        AutoExpandItem.__init__(self)
843        self.title = gettext("All")
844        self.path_title = "All Games"
845
846    def get_resource_name(self):
847        return "all"
848
849    def get_category_filter(self):
850        def category_filter(category):
851            return False
852
853        return category_filter
854
855        # def get_game_filter(self):
856        #     def game_filter(game_info):
857        #         return True
858        #     return game_filter
859
860
861class ShuffleMenuItem(MenuItem):
862    def __init__(self):
863        MenuItem.__init__(self)
864        self.title = gettext("Shuffle")
865        self.path_title = "Shuffle"
866        # FIXME: Sort game list in random order
867
868    def get_resource_name(self):
869        return "shuffle"
870
871    def activate(self, menu):
872        new_menu = create_item_menu(self.title)
873        menu_path = self.create_menu_path(menu)
874        new_menu.update_path(menu_path)
875        game_items = list(self.generate_game_items(menu_path))
876        random.shuffle(game_items)
877        for item in game_items:
878            new_menu.append(item)
879        return new_menu
880
881
882class LetterMenuItem(MenuItem):
883    def __init__(self):
884        MenuItem.__init__(self)
885        self.title = gettext("Letter")
886        self.path_title_active = "Choose Letter"
887
888    def get_resource_name(self):
889        return "letter"
890
891    def activate(self, menu):
892        print("LetterMenuItem.activate")
893        new_menu = create_item_menu(gettext("Select First Letter"))
894        menu_path = self.create_menu_path(menu)
895        new_menu.update_path(menu_path)
896        for letter in "#ABCDEFGHIJKLMNOPQRSTUVWXYZ":
897            item = LetterItem(letter)
898            new_menu.append(item)
899        return new_menu
900
901
902class LetterItem(AutoExpandItem):
903    def __init__(self, letter):
904        AutoExpandItem.__init__(self)
905        self.letter = letter
906        self.title = letter
907        self.path_title = letter
908
909    def get_resource_name(self):
910        if self.letter == "#":
911            return "0"
912        return self.letter.lower()
913
914    def get_category_filter(self):
915        def category_filter(category):
916            if category.__class__ == LetterMenuItem:
917                return False
918            return True
919
920        return category_filter
921
922    # def get_game_filter(self):
923    #     def game_filter(game_info):
924    #         if game_info.sort_title[0] == self.letter:
925    #             return True
926    #         if self.letter == "#":
927    #             if game_info.sort_title[0] in "0123456789":
928    #                 return True
929    #         return False
930    #     return game_filter
931
932    def get_filter_clause(self):
933        # FIXME: NUMBERS
934        # if self.letter == "#":
935        #     clause = ["AND (0 = 1"]
936        #     params = []
937        #     for c in "0123456789":
938        #         clause.append(" OR name LIKE ?")
939        #         params.append("{0}%".format(c))
940        #     clause.append(")")
941        #     return "".join(clause), params
942        # return "AND name LIKE ?", ["{0}%".format(self.letter)]
943        return "l:{0}".format(self.letter.lower()), []
944
945
946class YearMenuItem(MenuItem):
947    def __init__(self):
948        MenuItem.__init__(self)
949        self.title = gettext("Year")
950        self.path_title_active = "Choose Year"
951
952    def activate(self, menu):
953        print("YearMenuItem.activate")
954        menu = create_item_menu(gettext("Select Year"))
955        # for year in GameList().get().get_years(): # FIXME: GET YEARS FROM
956        # FILTERED GAME LIST
957        #     item = YearItem(year)
958        #     menu.append(item)
959        return menu
960
961
962class YearItem(AutoExpandItem):
963    def __init__(self, year):
964        AutoExpandItem.__init__(self)
965        self.year = year
966        self.title = str(year)
967        self.path_title = str(year)
968
969    def get_category_filter(self):
970        def category_filter(category):
971            if category.__class__ == YearMenuItem:
972                return False
973            return True
974
975        return category_filter
976
977        # def get_game_filter(self):
978        #     def game_filter(game_info):
979        #         if game_info.year == self.year:
980        #             return True
981        #         return False
982        #     return game_filter
983
984
985class KeywordMenuItem(MenuItem):
986    def __init__(self):
987        MenuItem.__init__(self)
988        self.title = gettext("Keyword")
989        self.path_title_active = "Choose Keyword"
990
991    def activate(self, menu):
992        print("KeywordMenuItem.activate")
993        new_menu = create_item_menu(gettext("Select Keyword"))
994        menu_path = self.create_menu_path(menu)
995        new_menu.update_path(menu_path)
996        category_filters = list(self.generate_category_filters(menu_path))
997
998        def check(cat):
999            for flt in category_filters:
1000                if not flt(cat):
1001                    return False
1002            return True
1003
1004        # for keyword in GameList().get().get_keywords():
1005        #     item = KeywordItem(keyword)
1006        #     if check(item):
1007        #         new_menu.append(item)
1008        return new_menu
1009
1010
1011class KeywordItem(AutoExpandItem):
1012    def __init__(self, keyword):
1013        AutoExpandItem.__init__(self)
1014        self.keyword = keyword
1015        self.title = keyword
1016        self.path_title = keyword
1017
1018    def get_category_filter(self):
1019        def category_filter(category):
1020            if category.__class__ == KeywordItem:
1021                if category.keyword == self.keyword:
1022                    return False
1023            return True
1024
1025        return category_filter
1026
1027        # def get_game_filter(self):
1028        #     def game_filter(game_info):
1029        #         if self.keyword in game_info.keywords:
1030        #             return True
1031        #         return False
1032        #     return game_filter
1033
1034
1035class GameItem(MenuItem):
1036    def __init__(self, game_info):
1037        MenuItem.__init__(self)
1038        self.game_info = game_info
1039        # self.id = id
1040        self.uuid = game_info[0]
1041        self.title = game_info[1]
1042
1043        # id, name, configurations, platform, ratio=0.75,
1044        #     screenratio=1.33, year="", publisher="", developer="",
1045        #     subtitlepos=-1
1046
1047        # when a game item is the selected item in the parent menu,
1048        # we are displaying category items
1049        self.path_title_active = "Add Filter"
1050
1051        # self.name = name
1052        self.configurations = []
1053        # self.platform = platform
1054        # print("self.platform = ", self.platform)
1055        # self.title = name
1056        # FIXME: Get correct year
1057        # self.year = year
1058        # self.publisher = publisher
1059        # self.developer = developer
1060        self.subtitle = ""
1061
1062        ratio = 0.75
1063        screenratio = 1.33
1064
1065        if ratio:
1066            self.ratio = ratio
1067        else:
1068            # if self.platform == "Game Boy":
1069            #     self.ratio = 1.0
1070            # elif self.platform == "Game Boy Color":
1071            #     self.ratio = 1.0
1072            # elif self.platform == "Game Boy Advance":
1073            #     self.ratio = 1.0
1074            # elif self.platform == "Super Nintendo":
1075            #     self.ratio = 1.33
1076            # elif self.platform == "Nintendo 64":
1077            #     self.ratio = 1.33
1078            # else:
1079            #     self.ratio = 0.75
1080            self.ratio = 0.75
1081        self.screenratio = screenratio or 1.33
1082
1083        # FIXME: REMOVE
1084        self.ratio = 0.75
1085
1086        # if subtitlepos > 0:
1087        #     self.title = name[:subtitlepos].strip()
1088        #     self.subtitle = name[subtitlepos:].strip()
1089        # elif subtitlepos < 0:
1090        #     self.supertitle = name[:-subtitlepos].strip()
1091        #     self.title = name[-subtitlepos:].strip()
1092        # else:
1093        #     self.fix_titles()
1094
1095    @property
1096    def name(self):
1097        return self.game_info[1]
1098
1099    # @property
1100    # def title(self):
1101    #     return self.game_info[1]
1102
1103    @property
1104    def platform(self):
1105        return self.game_info[2]
1106
1107    @property
1108    def year(self):
1109        return self.game_info[3]
1110
1111    @property
1112    def publisher(self):
1113        return self.game_info[4]
1114
1115    def fix_titles(self):
1116        try:
1117            title, subtitle = self.title.split(":", 1)
1118        except ValueError:
1119            pass
1120        else:
1121            # if len(title) >= 8:
1122            self.title = title
1123            self.subtitle = subtitle
1124        if not self.subtitle:
1125            if "(" in self.title:
1126                if self.title[-1] == ")":
1127                    pos = self.title.index("(")
1128                    self.subtitle = self.title[pos + 1 : -1].strip()
1129                    self.title = self.title[:pos].strip()
1130        # if not self.subtitle:
1131        #     if len(self.title) > 30 and " in " in self.title:
1132        #         pos = self.title.find(" in ")
1133        #         if pos > 8:
1134        #             self.subtitle = self.title[pos+4:].strip()
1135        #             self.title = self.title[:pos+4].strip()
1136        #             self.subtitle = self.subtitle[0].upper() +
1137        # self.subtitle[1:]
1138        if not self.subtitle:
1139            try:
1140                title, subtitle = self.title.split(" - ", 1)
1141            except ValueError:
1142                pass
1143            else:
1144                if len(title) >= 8:
1145                    self.title = title
1146                    self.subtitle = subtitle
1147        if not self.subtitle:
1148            pos = self.title.find(" and the ")
1149            if pos > 7:
1150                self.subtitle = self.title[pos:].strip()
1151                self.title = self.title[:pos].strip()
1152                # self.subtitle = self.subtitle[0].upper() + self.subtitle[1:]
1153
1154    def activate(self, menu):
1155        try:
1156            from arcade.glui.gamemenu import GameMenu
1157
1158            new_menu = GameMenu(self)
1159        except Exception:
1160            show_exception()
1161            print("returning None")
1162            return None
1163        return new_menu
1164
1165    def get_default_texture(self):
1166        return Texture.missing_cover
1167
1168    @memoize
1169    def get_image_path(self):
1170        cmp_name = GameNameUtil.create_cmpname(self.name)
1171
1172        # FIXME: FIXME: DISABLED TEMPORARILY
1173        # FIXME: USING 512-size only for now
1174
1175        # if False and os.path.exists("../fs-game-database/game/texture"):
1176        # if os.path.exists("../fs-game-database/game/texture"):
1177        #     base_path = "../fs-game-database/game/texture"
1178        #     path = os.path.join(base_path, NameUtil.create_cmpname(
1179        #             self.platform), cmp_name, "front-512.jpg")
1180        #             #self.platform), cmp_name, "front-1024.jpg")
1181        #     if os.path.exists(path):
1182        #         return path
1183        # #else:
1184        # base_path = os.path.join(pyapp.app.get_data_dir(), "texture")
1185        # if os.path.exists("c:\\data\\game\\info"):
1186        #     base_path = "c:\\data\\game\\info"
1187        # else:
1188        #     base_path = os.path.join(pyapp.app.get_data_dir(), "info")
1189        # base_path = os.path.join(GameCenter.data_dir, "info")
1190        # path = os.path.join(base_path, NameUtil.create_cmpname(self.platform),
1191        #         cmp_name, "front.jpg")
1192        # if not os.path.exists(path):
1193        #     base_path = "c:\\data\\game\\info"
1194        #     path = os.path.join(base_path, NameUtil.create_cmpname(
1195        #             self.platform), cmp_name, "front.jpg")
1196        #         #cmp_name, "front-1024.jpg")
1197        # if not os.path.exists(path):
1198        #     path = os.path.join(base_path,
1199        #             NameUtil.create_cmpname(self.platform),
1200        #             cmp_name, "front-512.jpg")
1201        # path = os.path.join(NameUtil.create_cmpname(self.platform),
1202        #         cmp_name, "front.jpg")
1203        # return path
1204        # return self.game_info[5] + "?s=512&t=jpg"
1205        if not self.game_info[5]:
1206            return None
1207        return self.game_info[5] + "?w=480&h=640&t=cc&f=jpg"
1208
1209    # @memoize
1210    # def get_image_files(self):
1211    #     path = self.get_image_path()
1212    #     if os.path.exists(path):
1213    #         return [path]
1214    #     return []
1215
1216    @memoize
1217    def get_image_files(self):
1218        path = self.get_image_path()
1219        # if path and os.path.exists(path):
1220        if path:
1221            return [path]
1222        return []
1223
1224    @memoize
1225    def get_screen_path(self, n):
1226        # cmp_name = NameUtil.create_cmpname(self.name)
1227        # base_path = os.path.join(GameCenter.data_dir, "info")
1228        # path = os.path.join(base_path, NameUtil.create_cmpname(self.platform),
1229        #         cmp_name, "screen{0}.png".format(n))
1230        # if not os.path.exists(path):
1231        #     base_path = "c:\\data\\game\\info"
1232        #     path = os.path.join(base_path, NameUtil.create_cmpname(
1233        #             self.platform), cmp_name, "screen{0}.png".format(n))
1234        # if not os.path.exists(path):
1235        #     return None
1236
1237        assert 1 <= n <= 5
1238        value = self.game_info[7 + n - 1]
1239        # if value:
1240        #     value = "sha1:" + value
1241
1242        # """
1243        # if n == 1:
1244        #     name = "screen1.png"
1245        # elif n == 2:
1246        #     name = "title.png"
1247        # else:
1248        #     name = "screen{0}.png".format(n - 1)
1249        # """
1250        # name = "screen{0}.png".format(n)
1251        # path = os.path.join(NameUtil.create_cmpname(
1252        #         self.platform), cmp_name, name)
1253        if not value:
1254            return None
1255        return value + "?s=1x"
1256
1257    def get_screen_texture(self, n):
1258        path = self.get_screen_path(n)
1259        # print("get_screen_texture", repr(path))
1260
1261        if path:
1262            # FIXME: LOAD WITH THE REST OF THE COVERS!
1263            TextureManager.get().load_images([path])
1264            try:
1265                texture = TextureManager.get().get_texture(path)
1266            except KeyError:
1267                texture = None
1268            if not texture:
1269                Render.get().dirty = DIRTY_WHILE_NOT_LOADED
1270            if texture is Texture.default_item:
1271                return Texture.missing_screenshot
1272            return texture
1273        return Texture.missing_screenshot
1274