Initial release
This commit is contained in:
+44
@@ -0,0 +1,44 @@
|
||||
##########################################################################################
|
||||
# VSTGUI Minesweeper Example Application
|
||||
##########################################################################################
|
||||
set(target Minesweeper)
|
||||
|
||||
set(${target}_sources
|
||||
"source/commands.h"
|
||||
"source/highscorelist.cpp"
|
||||
"source/highscorelist.h"
|
||||
"source/highscores.cpp"
|
||||
"source/highscores.h"
|
||||
"source/highscoreviewcontroller.cpp"
|
||||
"source/highscoreviewcontroller.h"
|
||||
"source/keepchildviewscentered.h"
|
||||
"source/minefieldviewcontroller.cpp"
|
||||
"source/minefieldviewcontroller.h"
|
||||
"source/model.cpp"
|
||||
"source/model.h"
|
||||
"source/myapp.cpp"
|
||||
"source/windowcontroller.cpp"
|
||||
"source/windowcontroller.h"
|
||||
)
|
||||
|
||||
set(Minesweeper_resources
|
||||
"resource/Window.uidesc"
|
||||
"resource/Minesweeper.icns"
|
||||
)
|
||||
|
||||
set(Minesweeper_font
|
||||
"resource/font/LCD14.otf"
|
||||
"resource/font/NotoEmoji-Regular.ttf"
|
||||
)
|
||||
|
||||
##########################################################################################
|
||||
vstgui_add_executable(${target} "${${target}_sources}" )
|
||||
vstgui_add_resources(${target} "${Minesweeper_resources}")
|
||||
vstgui_add_resources(${target} "${Minesweeper_font}" "Fonts")
|
||||
vstgui_set_target_bundle_id(${target} "vstgui.examples.minesweeper")
|
||||
vstgui_set_target_infoplist(${target} "resource/Info.plist")
|
||||
vstgui_set_target_rcfile(${target} "resource/Minesweeper.rc")
|
||||
vstgui_set_cxx_version(${target} ${VSTGUI_CXX_VERSION})
|
||||
target_include_directories(${target} PRIVATE ../../../../)
|
||||
set_target_properties(${target} PROPERTIES ${APP_PROPERTIES} ${VSTGUI_STANDALONE_EXAMPLES_FOLDER})
|
||||
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
+28
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Minesweeper</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>Minesweeper.icns</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2020 Arne Scheffler. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
Vendored
BIN
Binary file not shown.
Vendored
+1
@@ -0,0 +1 @@
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
APPL????
|
||||
Vendored
+665
@@ -0,0 +1,665 @@
|
||||
{
|
||||
"vstgui-ui-description": {
|
||||
"version": "1",
|
||||
"variables": {},
|
||||
"bitmaps": {},
|
||||
"fonts": {
|
||||
"control": {
|
||||
"font-name": "Arial",
|
||||
"size": "10"
|
||||
},
|
||||
"emoji": {
|
||||
"font-name": "Noto Emoji",
|
||||
"size": "12"
|
||||
},
|
||||
"highscore": {
|
||||
"font-name": "Arial",
|
||||
"size": "12"
|
||||
},
|
||||
"lcd": {
|
||||
"alternative-font-names": "LCD 14",
|
||||
"font-name": "LCD",
|
||||
"size": "14"
|
||||
},
|
||||
"lost": {
|
||||
"font-name": "Arial",
|
||||
"size": "20"
|
||||
},
|
||||
"time": {
|
||||
"font-name": "Arial",
|
||||
"size": "6"
|
||||
}
|
||||
},
|
||||
"colors": {
|
||||
"background": "#d9d9d9ff",
|
||||
"card.closed.back": "#a0a0a0ff",
|
||||
"card.closed.frame": "#000000ff",
|
||||
"card.flaged.back": "#0000001f",
|
||||
"card.flaged.frame": "#888888b4",
|
||||
"card.opened.back": "#ffffff00",
|
||||
"card.opened.frame": "#888888b4",
|
||||
"focus": "#40afe3ff",
|
||||
"highscore.font": "#000000ff",
|
||||
"label": "#000000ff",
|
||||
"lcd.font": "#ff0000ff",
|
||||
"lost.back": "#2c2c2c8c",
|
||||
"lost.font": "#ff0000ff",
|
||||
"textedit.font": "#ffffffff",
|
||||
"textedit.frame": "#9b9b9bff"
|
||||
},
|
||||
"gradients": {
|
||||
"Default TextButton Gradient": [
|
||||
{
|
||||
"rgba": "#dcdcdcff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#b4b4b4ff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"Default TextButton Gradient Highlighted": [
|
||||
{
|
||||
"rgba": "#b4b4b4ff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#646464ff",
|
||||
"start": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"control-tags": {
|
||||
"CloseHighscoreView": "9",
|
||||
"Cols": "1",
|
||||
"Flags": "3",
|
||||
"Mines": "2",
|
||||
"MouseMode": "6",
|
||||
"NewHighScoreName": "7",
|
||||
"NewHighScoreOK": "8",
|
||||
"Rows": "0",
|
||||
"Start": "5",
|
||||
"Time": "4"
|
||||
},
|
||||
"custom": {
|
||||
"UIGridController": {
|
||||
"Grids": "1x 1,5x 5,10x 10,12x 12,15x 15",
|
||||
"Size": "5, 5"
|
||||
},
|
||||
"UITemplateController": {
|
||||
"SelectedTemplate": "Window"
|
||||
},
|
||||
"UIEditController": {
|
||||
"EditViewScale": "1",
|
||||
"EditorSize": "0, 0, 1640, 1005",
|
||||
"SplitViewSize_0_0": "0.8151174668028600134306316249421797692776",
|
||||
"SplitViewSize_0_1": "0.1644535240040858048438110472488915547729",
|
||||
"SplitViewSize_1_0": "0.567926455566905019622936379164457321167",
|
||||
"SplitViewSize_1_1": "0.426966292134831448823462096697767265141",
|
||||
"SplitViewSize_2_0": "0.8073170731707317582248606413486413657665",
|
||||
"SplitViewSize_2_1": "0.1896341463414634165296490664331940934062",
|
||||
"TabSwitchValue": "6",
|
||||
"Version": "1"
|
||||
},
|
||||
"UIAttributesController": {
|
||||
"UIAttributesController": "contr"
|
||||
},
|
||||
"UIViewCreatorDataSource": {
|
||||
"SelectedRow": "30"
|
||||
},
|
||||
"UIDescFilePath": {
|
||||
"path": "/Users/scheffle/Source/vstgui/vstgui/standalone/examples/minesweeper/resource/Window.uidesc"
|
||||
},
|
||||
"UITagsDataSource": {
|
||||
"SelectedRow": "-1"
|
||||
},
|
||||
"UIColorsDataSource": {
|
||||
"SelectedRow": "8"
|
||||
},
|
||||
"UIFontsDataSource": {
|
||||
"SelectedRow": "2"
|
||||
},
|
||||
"UIGradientsDataSource": {
|
||||
"SelectedRow": "-1"
|
||||
},
|
||||
"UIBitmapsDataSource": {
|
||||
"SelectedRow": "-1"
|
||||
},
|
||||
"FocusDrawing": {
|
||||
"color": "focus",
|
||||
"enabled": "true",
|
||||
"width": "2"
|
||||
}
|
||||
},
|
||||
"templates": {
|
||||
"Window": {
|
||||
"attributes": {
|
||||
"autosize": "left right top bottom ",
|
||||
"background-color": "background",
|
||||
"background-color-draw-style": "filled and stroked",
|
||||
"class": "CViewContainer",
|
||||
"minSize": "364, 394",
|
||||
"mouse-enabled": "true",
|
||||
"opacity": "1",
|
||||
"origin": "0, 0",
|
||||
"size": "364, 394",
|
||||
"transparent": "false",
|
||||
"wants-focus": "false"
|
||||
},
|
||||
"children": {
|
||||
"CTextLabel": {
|
||||
"attributes": {
|
||||
"back-color": "~ BlackCColor",
|
||||
"background-offset": "0, 0",
|
||||
"class": "CTextLabel",
|
||||
"default-value": "0.5",
|
||||
"font": "control",
|
||||
"font-antialias": "true",
|
||||
"font-color": "label",
|
||||
"frame-color": "~ BlackCColor",
|
||||
"frame-width": "1",
|
||||
"max-value": "1",
|
||||
"min-value": "0",
|
||||
"mouse-enabled": "true",
|
||||
"opacity": "1",
|
||||
"origin": "10, 10",
|
||||
"round-rect-radius": "6",
|
||||
"shadow-color": "~ RedCColor",
|
||||
"size": "35, 20",
|
||||
"style-3D-in": "false",
|
||||
"style-3D-out": "false",
|
||||
"style-no-draw": "false",
|
||||
"style-no-frame": "false",
|
||||
"style-no-text": "false",
|
||||
"style-round-rect": "false",
|
||||
"style-shadow-text": "false",
|
||||
"text-alignment": "left",
|
||||
"text-inset": "0, 0",
|
||||
"text-rotation": "0",
|
||||
"text-shadow-offset": "1, 1",
|
||||
"title": "Mines :",
|
||||
"transparent": "true",
|
||||
"value-precision": "2",
|
||||
"wants-focus": "false",
|
||||
"wheel-inc-value": "0.1"
|
||||
}
|
||||
},
|
||||
"CTextLabel": {
|
||||
"attributes": {
|
||||
"back-color": "label",
|
||||
"background-offset": "0, 0",
|
||||
"class": "CTextLabel",
|
||||
"control-tag": "Flags",
|
||||
"default-value": "0.5",
|
||||
"font": "lcd",
|
||||
"font-antialias": "true",
|
||||
"font-color": "lcd.font",
|
||||
"frame-color": "textedit.frame",
|
||||
"frame-width": "-1",
|
||||
"max-value": "1",
|
||||
"min-value": "0",
|
||||
"mouse-enabled": "true",
|
||||
"opacity": "1",
|
||||
"origin": "45, 9",
|
||||
"round-rect-radius": "2",
|
||||
"shadow-color": "~ RedCColor",
|
||||
"size": "30, 22",
|
||||
"style-3D-in": "false",
|
||||
"style-3D-out": "false",
|
||||
"style-no-draw": "false",
|
||||
"style-no-frame": "false",
|
||||
"style-no-text": "false",
|
||||
"style-round-rect": "true",
|
||||
"style-shadow-text": "false",
|
||||
"text-alignment": "right",
|
||||
"text-inset": "5, 0",
|
||||
"text-rotation": "0",
|
||||
"text-shadow-offset": "1, 1",
|
||||
"title": "99",
|
||||
"transparent": "false",
|
||||
"value-precision": "2",
|
||||
"wants-focus": "false",
|
||||
"wheel-inc-value": "0.1"
|
||||
}
|
||||
},
|
||||
"CTextButton": {
|
||||
"attributes": {
|
||||
"autosize": "right top ",
|
||||
"class": "CTextButton",
|
||||
"control-tag": "Start",
|
||||
"default-value": "0.5",
|
||||
"font": "control",
|
||||
"frame-color": "label",
|
||||
"frame-color-highlighted": "label",
|
||||
"frame-width": "-1",
|
||||
"gradient": "Default TextButton Gradient",
|
||||
"gradient-highlighted": "Default TextButton Gradient Highlighted",
|
||||
"icon-position": "left",
|
||||
"icon-text-margin": "0",
|
||||
"kick-style": "true",
|
||||
"max-value": "1",
|
||||
"min-value": "0",
|
||||
"mouse-enabled": "true",
|
||||
"opacity": "1",
|
||||
"origin": "284, 11",
|
||||
"round-radius": "3",
|
||||
"size": "70, 18",
|
||||
"text-alignment": "center",
|
||||
"text-color": "label",
|
||||
"text-color-highlighted": "textedit.font",
|
||||
"title": "New Game",
|
||||
"transparent": "false",
|
||||
"wants-focus": "true",
|
||||
"wheel-inc-value": "0.1"
|
||||
}
|
||||
},
|
||||
"CViewContainer": {
|
||||
"attributes": {
|
||||
"autosize": "left right top bottom ",
|
||||
"background-color": "label",
|
||||
"background-color-draw-style": "stroked",
|
||||
"class": "CViewContainer",
|
||||
"custom-view-name": "MinefieldView",
|
||||
"mouse-enabled": "true",
|
||||
"opacity": "1",
|
||||
"origin": "10, 40",
|
||||
"size": "344, 344",
|
||||
"sub-controller": "MinefieldController",
|
||||
"transparent": "false",
|
||||
"wants-focus": "false"
|
||||
},
|
||||
"children": {
|
||||
"CViewContainer": {
|
||||
"attributes": {
|
||||
"autosize": "left right top bottom ",
|
||||
"background-color": "lost.back",
|
||||
"background-color-draw-style": "filled and stroked",
|
||||
"class": "CViewContainer",
|
||||
"custom-view-name": "LostView",
|
||||
"mouse-enabled": "false",
|
||||
"opacity": "0",
|
||||
"origin": "2, 2",
|
||||
"size": "338, 339",
|
||||
"transparent": "false",
|
||||
"wants-focus": "false"
|
||||
},
|
||||
"children": {
|
||||
"CTextLabel": {
|
||||
"attributes": {
|
||||
"autosize": "left right top bottom ",
|
||||
"back-color": "~ TransparentCColor",
|
||||
"background-offset": "0, 0",
|
||||
"class": "CTextLabel",
|
||||
"default-value": "0.5",
|
||||
"font": "lost",
|
||||
"font-antialias": "true",
|
||||
"font-color": "lost.font",
|
||||
"frame-color": "~ TransparentCColor",
|
||||
"frame-width": "1",
|
||||
"max-value": "1",
|
||||
"min-value": "0",
|
||||
"mouse-enabled": "false",
|
||||
"opacity": "1",
|
||||
"origin": "0, 0",
|
||||
"round-rect-radius": "6",
|
||||
"shadow-color": "label",
|
||||
"size": "339, 339",
|
||||
"style-3D-in": "false",
|
||||
"style-3D-out": "false",
|
||||
"style-no-draw": "false",
|
||||
"style-no-frame": "false",
|
||||
"style-no-text": "false",
|
||||
"style-round-rect": "false",
|
||||
"style-shadow-text": "true",
|
||||
"text-alignment": "center",
|
||||
"text-inset": "5, 0",
|
||||
"text-rotation": "0",
|
||||
"text-shadow-offset": "1, 1",
|
||||
"title": "EXPLODED",
|
||||
"transparent": "false",
|
||||
"value-precision": "2",
|
||||
"wants-focus": "false",
|
||||
"wheel-inc-value": "0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"CViewContainer": {
|
||||
"attributes": {
|
||||
"autosize": "left right top bottom ",
|
||||
"background-color": "lost.back",
|
||||
"background-color-draw-style": "filled and stroked",
|
||||
"class": "CViewContainer",
|
||||
"custom-view-name": "WonView",
|
||||
"mouse-enabled": "false",
|
||||
"opacity": "0",
|
||||
"origin": "2, 2",
|
||||
"size": "338, 339",
|
||||
"transparent": "false",
|
||||
"wants-focus": "false"
|
||||
},
|
||||
"children": {
|
||||
"CTextLabel": {
|
||||
"attributes": {
|
||||
"autosize": "left right top bottom ",
|
||||
"back-color": "lost.back",
|
||||
"background-offset": "0, 0",
|
||||
"class": "CTextLabel",
|
||||
"default-value": "0.5",
|
||||
"font": "lost",
|
||||
"font-antialias": "true",
|
||||
"font-color": "lost.font",
|
||||
"frame-color": "~ TransparentCColor",
|
||||
"frame-width": "1",
|
||||
"max-value": "1",
|
||||
"min-value": "0",
|
||||
"mouse-enabled": "true",
|
||||
"opacity": "0",
|
||||
"origin": "0, 0",
|
||||
"round-rect-radius": "6",
|
||||
"shadow-color": "label",
|
||||
"size": "338, 339",
|
||||
"style-3D-in": "false",
|
||||
"style-3D-out": "false",
|
||||
"style-no-draw": "false",
|
||||
"style-no-frame": "false",
|
||||
"style-no-text": "false",
|
||||
"style-round-rect": "false",
|
||||
"style-shadow-text": "true",
|
||||
"text-alignment": "center",
|
||||
"text-inset": "5, 0",
|
||||
"text-rotation": "0",
|
||||
"text-shadow-offset": "1, 1",
|
||||
"title": "FIELD CLEANED",
|
||||
"transparent": "true",
|
||||
"value-precision": "2",
|
||||
"wants-focus": "false",
|
||||
"wheel-inc-value": "0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"CTextLabel": {
|
||||
"attributes": {
|
||||
"back-color": "label",
|
||||
"background-offset": "0, 0",
|
||||
"class": "CTextLabel",
|
||||
"control-tag": "Time",
|
||||
"default-value": "0.5",
|
||||
"font": "lcd",
|
||||
"font-antialias": "true",
|
||||
"font-color": "lcd.font",
|
||||
"frame-color": "textedit.frame",
|
||||
"frame-width": "-1",
|
||||
"max-value": "1",
|
||||
"min-value": "0",
|
||||
"mouse-enabled": "true",
|
||||
"opacity": "1",
|
||||
"origin": "110, 9",
|
||||
"round-rect-radius": "2",
|
||||
"shadow-color": "~ RedCColor",
|
||||
"size": "40, 22",
|
||||
"style-3D-in": "false",
|
||||
"style-3D-out": "false",
|
||||
"style-no-draw": "false",
|
||||
"style-no-frame": "false",
|
||||
"style-no-text": "false",
|
||||
"style-round-rect": "true",
|
||||
"style-shadow-text": "false",
|
||||
"text-alignment": "right",
|
||||
"text-inset": "5, 0",
|
||||
"text-rotation": "0",
|
||||
"text-shadow-offset": "1, 1",
|
||||
"title": "000",
|
||||
"transparent": "false",
|
||||
"value-precision": "2",
|
||||
"wants-focus": "false",
|
||||
"wheel-inc-value": "0.1"
|
||||
}
|
||||
},
|
||||
"CTextLabel": {
|
||||
"attributes": {
|
||||
"back-color": "~ BlackCColor",
|
||||
"background-offset": "0, 0",
|
||||
"class": "CTextLabel",
|
||||
"default-value": "0.5",
|
||||
"font": "control",
|
||||
"font-antialias": "true",
|
||||
"font-color": "label",
|
||||
"frame-color": "~ BlackCColor",
|
||||
"frame-width": "1",
|
||||
"max-value": "1",
|
||||
"min-value": "0",
|
||||
"mouse-enabled": "true",
|
||||
"opacity": "1",
|
||||
"origin": "80, 10",
|
||||
"round-rect-radius": "6",
|
||||
"shadow-color": "~ RedCColor",
|
||||
"size": "30, 20",
|
||||
"style-3D-in": "false",
|
||||
"style-3D-out": "false",
|
||||
"style-no-draw": "false",
|
||||
"style-no-frame": "false",
|
||||
"style-no-text": "false",
|
||||
"style-round-rect": "false",
|
||||
"style-shadow-text": "false",
|
||||
"text-alignment": "left",
|
||||
"text-inset": "0, 0",
|
||||
"text-rotation": "0",
|
||||
"text-shadow-offset": "1, 1",
|
||||
"title": "Time :",
|
||||
"transparent": "true",
|
||||
"value-precision": "2",
|
||||
"wants-focus": "false",
|
||||
"wheel-inc-value": "0.1"
|
||||
}
|
||||
},
|
||||
"CViewContainer": {
|
||||
"attributes": {
|
||||
"autosize": "left right top bottom ",
|
||||
"background-color": "lost.back",
|
||||
"background-color-draw-style": "filled and stroked",
|
||||
"class": "CViewContainer",
|
||||
"custom-view-name": "MainView",
|
||||
"mouse-enabled": "false",
|
||||
"opacity": "0",
|
||||
"origin": "0, 0",
|
||||
"size": "365, 395",
|
||||
"sub-controller": "NewHighScoreViewController",
|
||||
"transparent": "false",
|
||||
"wants-focus": "false"
|
||||
},
|
||||
"children": {
|
||||
"CMultiLineTextLabel": {
|
||||
"attributes": {
|
||||
"auto-height": "false",
|
||||
"back-color": "card.closed.frame",
|
||||
"background-offset": "0, 0",
|
||||
"class": "CMultiLineTextLabel",
|
||||
"default-value": "0.5",
|
||||
"font": "highscore",
|
||||
"font-antialias": "true",
|
||||
"font-color": "textedit.font",
|
||||
"frame-color": "card.closed.frame",
|
||||
"frame-width": "1",
|
||||
"line-layout": "wrap",
|
||||
"max-value": "1",
|
||||
"min-value": "0",
|
||||
"mouse-enabled": "true",
|
||||
"opacity": "1",
|
||||
"origin": "40, 80",
|
||||
"round-rect-radius": "3",
|
||||
"shadow-color": "lcd.font",
|
||||
"size": "285, 56.3965",
|
||||
"style-3D-in": "false",
|
||||
"style-3D-out": "false",
|
||||
"style-no-draw": "false",
|
||||
"style-no-frame": "false",
|
||||
"style-no-text": "false",
|
||||
"style-round-rect": "true",
|
||||
"style-shadow-text": "false",
|
||||
"text-alignment": "center",
|
||||
"text-inset": "0, 5",
|
||||
"text-rotation": "0",
|
||||
"text-shadow-offset": "1, 1",
|
||||
"title": "You have a new HighScore!\\n\\nPlease enter your name:",
|
||||
"transparent": "false",
|
||||
"value-precision": "2",
|
||||
"wants-focus": "false",
|
||||
"wheel-inc-value": "0.1"
|
||||
}
|
||||
},
|
||||
"CTextEdit": {
|
||||
"attributes": {
|
||||
"back-color": "card.closed.frame",
|
||||
"background-offset": "0, 0",
|
||||
"class": "CTextEdit",
|
||||
"control-tag": "NewHighScoreName",
|
||||
"default-value": "0.5",
|
||||
"font": "highscore",
|
||||
"font-antialias": "true",
|
||||
"font-color": "textedit.font",
|
||||
"frame-color": "card.closed.frame",
|
||||
"frame-width": "1",
|
||||
"immediate-text-change": "false",
|
||||
"max-value": "1",
|
||||
"min-value": "0",
|
||||
"mouse-enabled": "true",
|
||||
"opacity": "1",
|
||||
"origin": "41, 143",
|
||||
"placeholder-title": "Name",
|
||||
"round-rect-radius": "3",
|
||||
"secure-style": "false",
|
||||
"shadow-color": "lcd.font",
|
||||
"size": "285, 20",
|
||||
"style-3D-in": "false",
|
||||
"style-3D-out": "false",
|
||||
"style-doubleclick": "false",
|
||||
"style-no-draw": "false",
|
||||
"style-no-frame": "false",
|
||||
"style-no-text": "false",
|
||||
"style-round-rect": "true",
|
||||
"style-shadow-text": "false",
|
||||
"text-alignment": "center",
|
||||
"text-inset": "0, 0",
|
||||
"text-rotation": "0",
|
||||
"text-shadow-offset": "1, 1",
|
||||
"transparent": "false",
|
||||
"value-precision": "2",
|
||||
"wants-focus": "true",
|
||||
"wheel-inc-value": "0.1"
|
||||
}
|
||||
},
|
||||
"CTextButton": {
|
||||
"attributes": {
|
||||
"class": "CTextButton",
|
||||
"control-tag": "NewHighScoreOK",
|
||||
"default-value": "0.5",
|
||||
"font": "control",
|
||||
"frame-color": "label",
|
||||
"frame-color-highlighted": "label",
|
||||
"frame-width": "-1",
|
||||
"gradient": "Default TextButton Gradient",
|
||||
"gradient-highlighted": "Default TextButton Gradient Highlighted",
|
||||
"icon-position": "left",
|
||||
"icon-text-margin": "0",
|
||||
"kick-style": "false",
|
||||
"max-value": "1",
|
||||
"min-value": "0",
|
||||
"mouse-enabled": "false",
|
||||
"opacity": "1",
|
||||
"origin": "133, 176",
|
||||
"round-radius": "3",
|
||||
"size": "100, 18",
|
||||
"text-alignment": "center",
|
||||
"text-color": "label",
|
||||
"text-color-highlighted": "textedit.font",
|
||||
"title": "OK",
|
||||
"transparent": "false",
|
||||
"wants-focus": "true",
|
||||
"wheel-inc-value": "0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"CViewContainer": {
|
||||
"attributes": {
|
||||
"autosize": "left right top bottom ",
|
||||
"background-color": "background",
|
||||
"background-color-draw-style": "filled and stroked",
|
||||
"class": "CViewContainer",
|
||||
"mouse-enabled": "false",
|
||||
"opacity": "0",
|
||||
"origin": "15, 45",
|
||||
"size": "335, 335",
|
||||
"sub-controller": "HighScoreViewController",
|
||||
"transparent": "false",
|
||||
"wants-focus": "false"
|
||||
},
|
||||
"children": {
|
||||
"CScrollView": {
|
||||
"attributes": {
|
||||
"auto-drag-scrolling": "false",
|
||||
"auto-hide-scrollbars": "false",
|
||||
"background-color": "~ BlackCColor",
|
||||
"background-color-draw-style": "filled and stroked",
|
||||
"bordered": "true",
|
||||
"class": "CScrollView",
|
||||
"container-size": "315, 259.091",
|
||||
"custom-view-name": "DataBrowser",
|
||||
"follow-focus-view": "false",
|
||||
"horizontal-scrollbar": "false",
|
||||
"mouse-enabled": "true",
|
||||
"opacity": "1",
|
||||
"origin": "10, 10",
|
||||
"overlay-scrollbars": "false",
|
||||
"scrollbar-background-color": "#ffffffc8",
|
||||
"scrollbar-frame-color": "~ BlackCColor",
|
||||
"scrollbar-scroller-color": "~ BlueCColor",
|
||||
"scrollbar-width": "16",
|
||||
"size": "315, 285",
|
||||
"sub-controller": "DataBrowserController",
|
||||
"transparent": "true",
|
||||
"vertical-scrollbar": "false",
|
||||
"wants-focus": "false"
|
||||
}
|
||||
},
|
||||
"CTextButton": {
|
||||
"attributes": {
|
||||
"class": "CTextButton",
|
||||
"control-tag": "CloseHighscoreView",
|
||||
"default-value": "0.5",
|
||||
"font": "control",
|
||||
"frame-color": "label",
|
||||
"frame-color-highlighted": "label",
|
||||
"frame-width": "-1",
|
||||
"gradient": "Default TextButton Gradient",
|
||||
"gradient-highlighted": "Default TextButton Gradient Highlighted",
|
||||
"icon-position": "left",
|
||||
"icon-text-margin": "0",
|
||||
"kick-style": "false",
|
||||
"max-value": "1",
|
||||
"min-value": "0",
|
||||
"mouse-enabled": "true",
|
||||
"opacity": "1",
|
||||
"origin": "135, 305",
|
||||
"round-radius": "3",
|
||||
"size": "70, 18",
|
||||
"text-alignment": "center",
|
||||
"text-color": "label",
|
||||
"text-color-highlighted": "textedit.font",
|
||||
"title": "Close",
|
||||
"transparent": "false",
|
||||
"wants-focus": "true",
|
||||
"wheel-inc-value": "0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
engine/vendor/vst3sdk/vstgui4/vstgui/standalone/examples/minesweeper/resource/font/LCD14_LICENSE.ttx
Vendored
+92
@@ -0,0 +1,92 @@
|
||||
Copyright (c) 2015 Fredrick Brennan (http://8type.net)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
BIN
Binary file not shown.
+34
@@ -0,0 +1,34 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vstgui/standalone/include/icommand.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static constexpr IdStringPtr GameGroup = "Game";
|
||||
static constexpr IdStringPtr ToggleHighscores = "Toggle Highscores";
|
||||
|
||||
static const Command NewGameCommand {GameGroup, "New Game"};
|
||||
static const Command NewBeginnerGameCommand {GameGroup, "New Beginner Game"};
|
||||
static const Command NewIntermediateGameCommand {GameGroup, "New Intermediate Game"};
|
||||
static const Command NewExpertGameCommand {GameGroup, "New Expert Game"};
|
||||
static const Command ToggleHighscoresCommand {GameGroup, ToggleHighscores};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static constexpr IdStringPtr MouseMode = "Use Mouse Mode";
|
||||
static constexpr IdStringPtr TouchpadMode = "Use Touchpad Mode";
|
||||
|
||||
static const Command MouseModeCommand {GameGroup, MouseMode};
|
||||
static const Command TouchpadModeCommand {GameGroup, TouchpadMode};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
Vendored
+171
@@ -0,0 +1,171 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "highscorelist.h"
|
||||
#include "vstgui/uidescription/cstream.h"
|
||||
#include <algorithm>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
namespace {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
UTF8String readUntil (char separator, CFileStream& stream)
|
||||
{
|
||||
std::string str;
|
||||
std::string::value_type character;
|
||||
while (stream.readRaw (&character, sizeof (character)) == sizeof (character))
|
||||
{
|
||||
if (character == separator)
|
||||
break;
|
||||
str += character;
|
||||
}
|
||||
return {std::move (str)};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
UTF8String replaceChars (const UTF8String& str, std::initializer_list<char> characters,
|
||||
char replacement)
|
||||
{
|
||||
std::string result;
|
||||
auto start = str.begin ();
|
||||
auto current = start;
|
||||
while (current != str.end ())
|
||||
{
|
||||
for (const auto& character : characters)
|
||||
{
|
||||
if (*current == character)
|
||||
{
|
||||
if (start != current)
|
||||
result.append (start.base (), current.base ());
|
||||
if (replacement)
|
||||
result += replacement;
|
||||
start = current;
|
||||
++start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
++current;
|
||||
}
|
||||
if (start != current)
|
||||
result.append (start.base (), current.base ());
|
||||
|
||||
return {std::move (result)};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // anonymous
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
Optional<HighScoreListModel> LoadHighScoreListModel (const UTF8String& path)
|
||||
{
|
||||
CFileStream stream;
|
||||
if (!stream.open (path.data (), CFileStream::kReadMode))
|
||||
return {};
|
||||
|
||||
HighScoreListModel list;
|
||||
while (!stream.isEndOfFile ())
|
||||
{
|
||||
auto secondsStr = readUntil (':', stream);
|
||||
if (auto seconds = UTF8StringView (secondsStr).toNumber<uint32_t> ())
|
||||
{
|
||||
auto name = readUntil (':', stream);
|
||||
auto dateStr = readUntil ('\n', stream);
|
||||
if (auto date = UTF8StringView (dateStr).toNumber<uint32_t> ())
|
||||
{
|
||||
list.addHighscore (name, *seconds, *date);
|
||||
}
|
||||
}
|
||||
else if (!stream.isEndOfFile ())
|
||||
return {};
|
||||
}
|
||||
return {std::move (list)};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool SaveHighScoreListModel (const HighScoreListModel& list, const UTF8String& path)
|
||||
{
|
||||
CFileStream stream;
|
||||
if (!stream.open (path.data (), CFileStream::kWriteMode | CFileStream::kTruncateMode))
|
||||
return false;
|
||||
|
||||
for (auto& element : list)
|
||||
{
|
||||
if (!element.valid ())
|
||||
break;
|
||||
stream << std::to_string (element.seconds);
|
||||
stream << std::string (1, ':');
|
||||
stream << element.name.getString ();
|
||||
stream << std::string (1, ':');
|
||||
stream << std::to_string (element.date);
|
||||
stream << std::string (1, '\n');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void HighScoreListModel::clear ()
|
||||
{
|
||||
std::for_each (list.begin (), list.end (), [] (auto& sel) { sel = {}; });
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
auto HighScoreListModel::highscorePosition (uint32_t seconds) -> ListIterator
|
||||
{
|
||||
return std::find_if (list.begin (), list.end (),
|
||||
[seconds] (const auto& entry) { return entry.seconds > seconds; });
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
auto HighScoreListModel::highscorePosition (uint32_t seconds) const -> ListConstIterator
|
||||
{
|
||||
return std::find_if (list.begin (), list.end (),
|
||||
[seconds] (const auto& entry) { return entry.seconds > seconds; });
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
Optional<size_t> HighScoreListModel::isHighScore (uint32_t seconds) const
|
||||
{
|
||||
auto pos = highscorePosition (seconds);
|
||||
if (pos == list.end ())
|
||||
return {};
|
||||
return {static_cast<size_t> (std::distance (list.begin (), pos))};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
Optional<size_t> HighScoreListModel::addHighscore (UTF8StringPtr name, uint32_t seconds,
|
||||
std::time_t date)
|
||||
{
|
||||
auto it = highscorePosition (seconds);
|
||||
if (it == list.end ())
|
||||
return {};
|
||||
|
||||
auto pos = std::distance (list.begin (), it);
|
||||
auto end = list.begin ();
|
||||
std::advance (end, list.size () - 1);
|
||||
std::move_backward (it, end, list.end ());
|
||||
list[pos].name = replaceChars (name, {':', '\n'}, '_');
|
||||
list[pos].seconds = seconds;
|
||||
list[pos].date = (date == 0) ? std::time (nullptr) : date;
|
||||
return Optional<size_t> (pos);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
auto HighScoreListModel::begin () const -> ListConstIterator
|
||||
{
|
||||
return list.begin ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
auto HighScoreListModel::end () const -> ListConstIterator
|
||||
{
|
||||
return list.end ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
Vendored
+98
@@ -0,0 +1,98 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vstgui/lib/cstring.h"
|
||||
#include "vstgui/lib/optional.h"
|
||||
#include <array>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class HighScoreListModel
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------
|
||||
static constexpr size_t Size = 10u;
|
||||
//------------------------------------------------------------------------
|
||||
struct Entry
|
||||
{
|
||||
uint32_t seconds {std::numeric_limits<uint32_t>::max ()};
|
||||
std::time_t date {};
|
||||
UTF8String name;
|
||||
|
||||
bool valid () const { return seconds != std::numeric_limits<uint32_t>::max (); }
|
||||
};
|
||||
|
||||
HighScoreListModel () { clear (); }
|
||||
HighScoreListModel (HighScoreListModel&&) = default;
|
||||
HighScoreListModel& operator= (HighScoreListModel&&) = default;
|
||||
|
||||
void clear ();
|
||||
Optional<size_t> addHighscore (UTF8StringPtr name, uint32_t seconds, std::time_t date = 0);
|
||||
|
||||
Optional<size_t> isHighScore (uint32_t seconds) const;
|
||||
|
||||
using List = std::array<Entry, Size>;
|
||||
using ListIterator = List::iterator;
|
||||
using ListConstIterator = List::const_iterator;
|
||||
|
||||
ListConstIterator begin () const;
|
||||
ListConstIterator end () const;
|
||||
//------------------------------------------------------------------------
|
||||
private:
|
||||
ListIterator highscorePosition (uint32_t seconds);
|
||||
ListConstIterator highscorePosition (uint32_t seconds) const;
|
||||
|
||||
List list;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
Optional<HighScoreListModel> LoadHighScoreListModel (const UTF8String& path);
|
||||
bool SaveHighScoreListModel (const HighScoreListModel& list, const UTF8String& path);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class HighScoreList
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<HighScoreList> make (const UTF8String& path)
|
||||
{
|
||||
auto instance = std::make_shared<HighScoreList> ();
|
||||
instance->path = path;
|
||||
if (auto l = LoadHighScoreListModel (path))
|
||||
{
|
||||
instance->list = std::move (*l);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
const UTF8String& getPath () const { return path; }
|
||||
const HighScoreListModel& get () const { return list; }
|
||||
HighScoreListModel& get () { return list; }
|
||||
|
||||
Optional<size_t> addHighscore (UTF8StringPtr name, uint32_t seconds, std::time_t date = 0)
|
||||
{
|
||||
auto res = list.addHighscore (name, seconds, date);
|
||||
if (res)
|
||||
save ();
|
||||
return res;
|
||||
}
|
||||
Optional<size_t> isHighScore (uint32_t seconds) const { return list.isHighScore (seconds); }
|
||||
|
||||
private:
|
||||
void save () { SaveHighScoreListModel (list, path); }
|
||||
UTF8String path;
|
||||
HighScoreListModel list;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "highscores.h"
|
||||
#include "vstgui/standalone/include/iapplication.h"
|
||||
#include "vstgui/standalone/include/icommondirectories.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
HighScores& HighScores::instance ()
|
||||
{
|
||||
static HighScores gInstance;
|
||||
return gInstance;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
std::shared_ptr<HighScoreList> HighScores::get (uint32_t rows, uint32_t cols, uint32_t mines)
|
||||
{
|
||||
auto path = IApplication::instance ().getCommonDirectories ().get (
|
||||
CommonDirectoryLocation::AppPreferencesPath, {}, true);
|
||||
if (!path)
|
||||
return nullptr;
|
||||
*path += getHighscoreListName (rows, cols, mines);
|
||||
|
||||
auto it = lists.find (path->getString ());
|
||||
if (it != lists.end ())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto list = HighScoreList::make (*path);
|
||||
lists.insert ({path->getString (), list});
|
||||
return list;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
UTF8String HighScores::getHighscoreListName (uint32_t rows, uint32_t cols, uint32_t mines)
|
||||
{
|
||||
return toString (rows) + "x" + toString (cols) + "x" + toString (mines) + ".highscore";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "highscorelist.h"
|
||||
#include <unordered_map>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class HighScores
|
||||
{
|
||||
public:
|
||||
static HighScores& instance ();
|
||||
static UTF8String getHighscoreListName (uint32_t rows, uint32_t cols, uint32_t mines);
|
||||
|
||||
std::shared_ptr<HighScoreList> get (uint32_t rows, uint32_t cols, uint32_t mines);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::shared_ptr<HighScoreList>> lists;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
+224
@@ -0,0 +1,224 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "highscoreviewcontroller.h"
|
||||
#include "keepchildviewscentered.h"
|
||||
#include "vstgui/lib/cdatabrowser.h"
|
||||
#include "vstgui/lib/cdrawcontext.h"
|
||||
#include "vstgui/uidescription/iuidescription.h"
|
||||
#include "vstgui/uidescription/uiattributes.h"
|
||||
#include <cassert>
|
||||
#include <ctime>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
HighScoreViewController::HighScoreViewController (IController* parent)
|
||||
: DelegationController (parent)
|
||||
{
|
||||
columnWidths[0] = 0.06;
|
||||
columnWidths[1] = 0.14;
|
||||
columnWidths[2] = 0.5;
|
||||
columnWidths[3] = 0.3;
|
||||
font = kSystemFont;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void HighScoreViewController::setHighScoreList (const std::shared_ptr<HighScoreList>& l)
|
||||
{
|
||||
list = l;
|
||||
if (dataBrowser)
|
||||
dataBrowser->recalculateLayout ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool HighScoreViewController::isVisible () const
|
||||
{
|
||||
if (dataBrowser)
|
||||
{
|
||||
if (auto parent = dataBrowser->getParentView ())
|
||||
return parent->isVisible ();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void HighScoreViewController::show ()
|
||||
{
|
||||
if (!dataBrowser)
|
||||
return;
|
||||
if (auto parent = dataBrowser->getParentView ())
|
||||
{
|
||||
parent->setMouseEnabled (true);
|
||||
parent->setAlphaValue (1.f);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void HighScoreViewController::hide ()
|
||||
{
|
||||
if (!dataBrowser)
|
||||
return;
|
||||
if (auto parent = dataBrowser->getParentView ())
|
||||
{
|
||||
parent->setAlphaValue (0.f);
|
||||
parent->setMouseEnabled (false);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void HighScoreViewController::dbAttached (CDataBrowser* browser)
|
||||
{
|
||||
dataBrowser = browser;
|
||||
if (auto parent = browser->getParentView ())
|
||||
{
|
||||
assert (parent->asViewContainer ());
|
||||
keepChildViewsCentered (parent->asViewContainer ());
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void HighScoreViewController::dbRemoved (CDataBrowser* browser)
|
||||
{
|
||||
dataBrowser = nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t HighScoreViewController::dbGetNumRows (CDataBrowser* browser)
|
||||
{
|
||||
return HighScoreListModel::Size;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t HighScoreViewController::dbGetNumColumns (CDataBrowser* browser)
|
||||
{
|
||||
return NumCols;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CCoord HighScoreViewController::dbGetRowHeight (CDataBrowser* browser)
|
||||
{
|
||||
auto height = browser->getHeight () / (HighScoreListModel::Size + 1) - 1;
|
||||
if (font->getSize () != height * 0.6)
|
||||
font->setSize (height * 0.6);
|
||||
return height;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CCoord HighScoreViewController::dbGetCurrentColumnWidth (int32_t index, CDataBrowser* browser)
|
||||
{
|
||||
if (index >= 0 && index < NumCols)
|
||||
return browser->getWidth () * columnWidths[index];
|
||||
return 10;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool HighScoreViewController::dbGetLineWidthAndColor (CCoord& width, CColor& color,
|
||||
CDataBrowser* browser)
|
||||
{
|
||||
width = 1.;
|
||||
color = kBlackCColor;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void HighScoreViewController::dbDrawHeader (CDrawContext* context, const CRect& size,
|
||||
int32_t column, int32_t flags, CDataBrowser* browser)
|
||||
{
|
||||
context->setFont (font);
|
||||
context->setFontColor (fontColor);
|
||||
UTF8String text;
|
||||
switch (column)
|
||||
{
|
||||
case 1: text = "Sec"; break;
|
||||
case 2: text = "Name"; break;
|
||||
case 3: text = "Date"; break;
|
||||
default: break;
|
||||
}
|
||||
if (!text.empty ())
|
||||
{
|
||||
context->drawString (text, size);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void HighScoreViewController::dbDrawCell (CDrawContext* context, const CRect& size, int32_t row,
|
||||
int32_t column, int32_t flags, CDataBrowser* browser)
|
||||
{
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
auto entry = list->get ().begin ();
|
||||
std::advance (entry, row);
|
||||
if (entry == list->get ().end ())
|
||||
return;
|
||||
bool valid = entry->valid ();
|
||||
context->setFont (font);
|
||||
context->setFontColor (fontColor);
|
||||
UTF8String text = "-";
|
||||
CHoriTxtAlign align = kCenterText;
|
||||
CRect r = size;
|
||||
switch (column)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
text = toString (row + 1) + ".";
|
||||
align = kRightText;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
if (valid)
|
||||
text = toString (entry->seconds);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (valid)
|
||||
{
|
||||
text = entry->name;
|
||||
align = kLeftText;
|
||||
r.left += 5.;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
if (valid)
|
||||
{
|
||||
char mbstr[100];
|
||||
if (std::strftime (mbstr, sizeof (mbstr), "%F", std::localtime (&entry->date)))
|
||||
{
|
||||
text = mbstr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
context->drawString (text, r, align);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CView* HighScoreViewController::createView (const UIAttributes& attributes,
|
||||
const IUIDescription* description)
|
||||
{
|
||||
const auto attr = attributes.getAttributeValue (IUIDescription::kCustomViewName);
|
||||
if (attr && *attr == "DataBrowser")
|
||||
{
|
||||
if (auto f = description->getFont ("highscore"))
|
||||
font = f;
|
||||
description->getColor ("highscore.font", fontColor);
|
||||
return new CDataBrowser ({}, this, CDataBrowser::kDrawHeader | CDataBrowser::kDrawRowLines,
|
||||
0.);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "highscorelist.h"
|
||||
#include "vstgui/lib/ccolor.h"
|
||||
#include "vstgui/lib/cfont.h"
|
||||
#include "vstgui/lib/idatabrowserdelegate.h"
|
||||
#include "vstgui/uidescription/delegationcontroller.h"
|
||||
#include <array>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class HighScoreViewController final : public DelegationController,
|
||||
public DataBrowserDelegateAdapter,
|
||||
public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
HighScoreViewController (IController* parent);
|
||||
|
||||
void setHighScoreList (const std::shared_ptr<HighScoreList>& list);
|
||||
|
||||
void show ();
|
||||
void hide ();
|
||||
bool isVisible () const;
|
||||
|
||||
private:
|
||||
int32_t dbGetNumRows (CDataBrowser* browser) override;
|
||||
int32_t dbGetNumColumns (CDataBrowser* browser) override;
|
||||
CCoord dbGetRowHeight (CDataBrowser* browser) override;
|
||||
CCoord dbGetCurrentColumnWidth (int32_t index, CDataBrowser* browser) override;
|
||||
void dbDrawHeader (CDrawContext* context, const CRect& size, int32_t column, int32_t flags,
|
||||
CDataBrowser* browser) override;
|
||||
void dbDrawCell (CDrawContext* context, const CRect& size, int32_t row, int32_t column,
|
||||
int32_t flags, CDataBrowser* browser) override;
|
||||
CView* createView (const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
void dbAttached (CDataBrowser* browser) override;
|
||||
void dbRemoved (CDataBrowser* browser) override;
|
||||
bool dbGetLineWidthAndColor (CCoord& width, CColor& color, CDataBrowser* browser) override;
|
||||
|
||||
static constexpr const size_t NumCols = 4;
|
||||
|
||||
SharedPointer<CFontDesc> font;
|
||||
CColor fontColor {kBlackCColor};
|
||||
CDataBrowser* dataBrowser {nullptr};
|
||||
std::shared_ptr<HighScoreList> list;
|
||||
std::array<CCoord, NumCols> columnWidths;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
engine/vendor/vst3sdk/vstgui4/vstgui/standalone/examples/minesweeper/source/keepchildviewscentered.h
Vendored
+62
@@ -0,0 +1,62 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vstgui/lib/cviewcontainer.h"
|
||||
#include "vstgui/lib/iviewlistener.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void keepChildViewsCentered (CViewContainer* view)
|
||||
{
|
||||
//------------------------------------------------------------------------
|
||||
class CenteredViewHandler : public ViewListenerAdapter
|
||||
{
|
||||
public:
|
||||
CenteredViewHandler (CViewContainer* container) : parent (container)
|
||||
{
|
||||
parent->registerViewListener (this);
|
||||
}
|
||||
|
||||
void viewSizeChanged (CView* view, const CRect& oldSize) override
|
||||
{
|
||||
if (!view->isAttached ())
|
||||
return;
|
||||
auto viewSize = view->getViewSize ();
|
||||
auto diffX = viewSize.getWidth () - oldSize.getWidth ();
|
||||
auto diffY = viewSize.getHeight () - oldSize.getHeight ();
|
||||
if (diffX == 0. && diffY == 0.)
|
||||
return;
|
||||
diffX *= 0.5;
|
||||
diffY *= 0.5;
|
||||
parent->forEachChild ([&] (auto& child) {
|
||||
auto vs = child->getViewSize ();
|
||||
vs.offset (diffX, diffY);
|
||||
child->setViewSize (vs);
|
||||
child->setMouseableArea (vs);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
void viewWillDelete (CView* view) override
|
||||
{
|
||||
view->unregisterViewListener (this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
CViewContainer* parent {nullptr};
|
||||
};
|
||||
|
||||
new CenteredViewHandler (view);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
+430
@@ -0,0 +1,430 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "minefieldviewcontroller.h"
|
||||
#include "vstgui/lib/animation/animations.h"
|
||||
#include "vstgui/lib/animation/timingfunctions.h"
|
||||
#include "vstgui/lib/cdatabrowser.h"
|
||||
#include "vstgui/lib/cdrawcontext.h"
|
||||
#include "vstgui/lib/cvstguitimer.h"
|
||||
#include "vstgui/standalone/include/helpers/value.h"
|
||||
#include "vstgui/uidescription/iuidescription.h"
|
||||
#include "vstgui/uidescription/uiattributes.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
MinefieldViewController::MinefieldViewController (IValue& flagsValue, IValue& timeValue,
|
||||
IController* parent,
|
||||
WonCallbackFunc&& wonCallback)
|
||||
: DelegationController (parent)
|
||||
, flagsValue (flagsValue)
|
||||
, timeValue (timeValue)
|
||||
, wonCallback (std::move (wonCallback))
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::startGame (uint32_t rows, uint32_t cols, uint32_t mines)
|
||||
{
|
||||
if (lostView)
|
||||
{
|
||||
lostView->removeAllAnimations ();
|
||||
lostView->setAlphaValue (0.f);
|
||||
}
|
||||
if (wonView)
|
||||
{
|
||||
wonView->removeAllAnimations ();
|
||||
wonView->setAlphaValue (0.f);
|
||||
}
|
||||
model = std::make_unique<Model> (rows, cols, mines, this);
|
||||
numRows = rows;
|
||||
numCols = cols;
|
||||
updateCellSize (dataBrowser->getViewSize ().getSize ());
|
||||
Value::performSinglePlainEdit (flagsValue, model->getNumberOfMines ());
|
||||
Value::performSinglePlainEdit (timeValue, 0);
|
||||
startTime = {};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::setMouseMode (bool state)
|
||||
{
|
||||
mouseMode = state;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CView* MinefieldViewController::createView (const UIAttributes& attributes,
|
||||
const IUIDescription* description)
|
||||
{
|
||||
const auto attr = attributes.getAttributeValue (IUIDescription::kCustomViewName);
|
||||
if (attr && *attr == "MinefieldView")
|
||||
{
|
||||
description->getColor ("card.closed.frame", closedFrameColor);
|
||||
description->getColor ("card.closed.back", closedBackColor);
|
||||
description->getColor ("card.opened.frame", openedFrameColor);
|
||||
description->getColor ("card.opened.back", openedBackColor);
|
||||
description->getColor ("card.flaged.frame", flagedFrameColor);
|
||||
description->getColor ("card.flaged.back", flagedBackColor);
|
||||
if (auto f = description->getFont ("emoji"))
|
||||
emojiFont = *f;
|
||||
smallEmojiFont = emojiFont;
|
||||
if (dataBrowser)
|
||||
dataBrowser->unregisterViewListener (this);
|
||||
dataBrowser = nullptr;
|
||||
dataBrowser = new CDataBrowser ({}, this, 0, 0.);
|
||||
dataBrowser->registerViewListener (this);
|
||||
return dataBrowser;
|
||||
}
|
||||
return DelegationController::createView (attributes, description);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CView* MinefieldViewController::verifyView (CView* view, const UIAttributes& attributes,
|
||||
const IUIDescription* description)
|
||||
{
|
||||
const auto attr = attributes.getAttributeValue (IUIDescription::kCustomViewName);
|
||||
if (attr)
|
||||
{
|
||||
if (*attr == "LostView")
|
||||
{
|
||||
lostView = view;
|
||||
lostView->setAlphaValue (0.f);
|
||||
}
|
||||
else if (*attr == "WonView")
|
||||
{
|
||||
wonView = view;
|
||||
wonView->setAlphaValue (0.f);
|
||||
}
|
||||
}
|
||||
|
||||
return DelegationController::verifyView (view, attributes, description);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::onCellChanged (uint32_t row, uint32_t col)
|
||||
{
|
||||
if (!dataBrowser)
|
||||
return;
|
||||
auto r = dataBrowser->getCellBounds (CDataBrowser::Cell (row, col));
|
||||
r.extend (1., 1.);
|
||||
dataBrowser->invalidRect (r);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t MinefieldViewController::dbGetNumRows (CDataBrowser* browser)
|
||||
{
|
||||
return numRows;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t MinefieldViewController::dbGetNumColumns (CDataBrowser* browser)
|
||||
{
|
||||
return numCols;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CCoord MinefieldViewController::dbGetRowHeight (CDataBrowser* browser)
|
||||
{
|
||||
return cellSize.y;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CCoord MinefieldViewController::dbGetCurrentColumnWidth (int32_t index, CDataBrowser* browser)
|
||||
{
|
||||
return cellSize.x;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool MinefieldViewController::dbGetLineWidthAndColor (CCoord& width, CColor& color,
|
||||
CDataBrowser* browser)
|
||||
{
|
||||
width = 1;
|
||||
color = kBlackCColor;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::drawClosedCell (const CRect& r, CDrawContext& context) const
|
||||
{
|
||||
context.setFrameColor (closedFrameColor);
|
||||
context.setFillColor (closedBackColor);
|
||||
context.drawRect (r, kDrawFilledAndStroked);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::drawOpenCell (const CRect& r, CDrawContext& context) const
|
||||
{
|
||||
context.setFrameColor (openedFrameColor);
|
||||
context.setFillColor (openedBackColor);
|
||||
context.drawRect (r, kDrawFilledAndStroked);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::drawQuestionMark (const CRect& r, CDrawContext& context,
|
||||
CFontRef f) const
|
||||
{
|
||||
context.setFont (f);
|
||||
context.setFontColor (kRedCColor);
|
||||
context.drawString (QuestionMarkCharacter, r);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::drawQuestionMarkCell (const CRect& r, CDrawContext& context,
|
||||
CFontRef f) const
|
||||
{
|
||||
context.setFrameColor (flagedFrameColor);
|
||||
context.setFillColor (flagedBackColor);
|
||||
context.drawRect (r, kDrawFilledAndStroked);
|
||||
drawQuestionMark (r, context, f);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::drawFlag (const CRect& r, CDrawContext& context, CFontRef f) const
|
||||
{
|
||||
context.setFont (f);
|
||||
context.setFontColor (kRedCColor);
|
||||
context.drawString (FlagCharacter, r);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::drawFlaggedCell (const CRect& r, CDrawContext& context,
|
||||
CFontRef f) const
|
||||
{
|
||||
context.setFrameColor (flagedFrameColor);
|
||||
context.setFillColor (flagedBackColor);
|
||||
context.drawRect (r, kDrawFilledAndStroked);
|
||||
drawFlag (r, context, f);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::drawMinedCell (const CRect& r, CDrawContext& context,
|
||||
CFontRef f) const
|
||||
{
|
||||
context.setFont (f);
|
||||
context.setFontColor (kBlackCColor);
|
||||
context.drawString (BombCharacter, r);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::drawExplosionCell (const CRect& r, CDrawContext& context,
|
||||
CFontRef f) const
|
||||
{
|
||||
context.setFont (f);
|
||||
context.setFontColor (kRedCColor);
|
||||
context.drawString (ExplosionCharacter, r);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::drawCellNeighbours (const CRect& r, CDrawContext& context, CFontRef f,
|
||||
uint32_t neighbours)
|
||||
{
|
||||
if (neighbours == 0)
|
||||
return;
|
||||
auto valueStr = toString (neighbours);
|
||||
context.setFont (f);
|
||||
context.setFontColor (kBlackCColor);
|
||||
context.drawString (valueStr, r);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::dbDrawCell (CDrawContext* context, const CRect& size, int32_t row,
|
||||
int32_t column, int32_t flags, CDataBrowser* browser)
|
||||
{
|
||||
if (row < 0 || column < 0 || !model)
|
||||
return;
|
||||
context->setDrawMode (kAntiAliasing);
|
||||
context->setLineWidth (1.);
|
||||
CRect r (size);
|
||||
r.inset (1.5, 1.5);
|
||||
if (!model->isDone () && !model->isTrapped () && !model->isOpen (row, column))
|
||||
{
|
||||
if (model->isFlag (row, column))
|
||||
{
|
||||
drawFlaggedCell (r, *context, &emojiFont);
|
||||
}
|
||||
else if (model->isQuestion (row, column))
|
||||
{
|
||||
drawQuestionMarkCell (r, *context, &emojiFont);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawClosedCell (r, *context);
|
||||
}
|
||||
return;
|
||||
}
|
||||
drawOpenCell (r, *context);
|
||||
if (model->isMine (row, column))
|
||||
{
|
||||
if (model->isTrapMine (row, column))
|
||||
drawExplosionCell (r, *context, &emojiFont);
|
||||
else
|
||||
drawMinedCell (r, *context, &emojiFont);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto value = model->getNumberOfMinesNearby (row, column);
|
||||
drawCellNeighbours (r, *context, &font, value);
|
||||
}
|
||||
if (model->isFlag (row, column))
|
||||
{
|
||||
r.setWidth (r.getWidth () / 2.);
|
||||
r.setHeight (r.getHeight () / 2.);
|
||||
drawFlag (r, *context, &smallEmojiFont);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult MinefieldViewController::dbOnMouseDown (const CPoint& where,
|
||||
const CButtonState& buttons, int32_t row,
|
||||
int32_t column, CDataBrowser* browser)
|
||||
{
|
||||
ignoreMouseUp = false;
|
||||
if (!mouseMode && buttons.isLeftButton ())
|
||||
{
|
||||
mouseDownTimer = makeOwned<CVSTGUITimer> (
|
||||
[this, row, column] (auto) {
|
||||
mouseDownTimer = nullptr;
|
||||
if (!model->isOpen (row, column))
|
||||
{
|
||||
model->mark (row, column);
|
||||
checkGameOver ();
|
||||
}
|
||||
ignoreMouseUp = true;
|
||||
},
|
||||
60);
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult MinefieldViewController::dbOnMouseMoved (const CPoint& where,
|
||||
const CButtonState& buttons, int32_t row,
|
||||
int32_t column, CDataBrowser* browser)
|
||||
{
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult MinefieldViewController::dbOnMouseUp (const CPoint& where,
|
||||
const CButtonState& buttons, int32_t row,
|
||||
int32_t column, CDataBrowser* browser)
|
||||
{
|
||||
mouseDownTimer = nullptr;
|
||||
if (ignoreMouseUp || !model || row < 0 || column < 0 || model->isTrapped () || model->isDone ())
|
||||
return kMouseEventHandled;
|
||||
if (!model->isOpen (row, column))
|
||||
{
|
||||
if (buttons.isRightButton ())
|
||||
{
|
||||
model->mark (row, column);
|
||||
}
|
||||
else if (buttons.isLeftButton ())
|
||||
{
|
||||
if (!model->isFlag (row, column) && !model->isQuestion (row, column))
|
||||
model->open (row, column);
|
||||
else
|
||||
model->mark (row, column);
|
||||
}
|
||||
checkGameOver ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::checkGameOver ()
|
||||
{
|
||||
if (startTime == TimePoint {})
|
||||
{
|
||||
startTime = Clock::now ();
|
||||
gameTimer = makeOwned<CVSTGUITimer> ([this] (auto) { onTimer (); }, 1000);
|
||||
}
|
||||
Value::performSinglePlainEdit (flagsValue,
|
||||
model->getNumberOfMines () - model->getNumberOfFlags ());
|
||||
if (model->isDone () && !model->isTrapped ())
|
||||
{
|
||||
onGameWon ();
|
||||
}
|
||||
if (model->isTrapped ())
|
||||
{
|
||||
onGameLost ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::onGameLost ()
|
||||
{
|
||||
auto animView = lostView;
|
||||
if (auto vc = lostView->asViewContainer ())
|
||||
{
|
||||
animView = vc->getView (0);
|
||||
animView->setAlphaValue (0.f);
|
||||
lostView->setAlphaValue (1.f);
|
||||
}
|
||||
animView->addAnimation ("Lost", new Animation::AlphaValueAnimation (1.f),
|
||||
new Animation::RepeatTimingFunction (
|
||||
new Animation::CubicBezierTimingFunction (
|
||||
Animation::CubicBezierTimingFunction::easyInOut (250)),
|
||||
-1));
|
||||
gameTimer = nullptr;
|
||||
dataBrowser->invalid ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::onGameWon ()
|
||||
{
|
||||
auto animView = wonView;
|
||||
if (auto vc = wonView->asViewContainer ())
|
||||
{
|
||||
animView = vc->getView (0);
|
||||
animView->setAlphaValue (0.f);
|
||||
wonView->setAlphaValue (1.f);
|
||||
}
|
||||
animView->addAnimation ("Won", new Animation::AlphaValueAnimation (1.f),
|
||||
new Animation::RepeatTimingFunction (
|
||||
new Animation::CubicBezierTimingFunction (
|
||||
Animation::CubicBezierTimingFunction::easyInOut (400)),
|
||||
-1));
|
||||
gameTimer = nullptr;
|
||||
dataBrowser->invalid ();
|
||||
if (wonCallback)
|
||||
wonCallback (static_cast<int32_t> (Value::currentPlainValue (timeValue)));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::onTimer ()
|
||||
{
|
||||
auto now = Clock::now ();
|
||||
auto distance = std::chrono::duration_cast<std::chrono::seconds> (now - startTime).count ();
|
||||
if (distance >= maxTimeInSeconds)
|
||||
gameTimer = nullptr;
|
||||
Value::performSinglePlainEdit (timeValue, static_cast<IValue::Type> (distance));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::viewSizeChanged (CView* view, const CRect& oldSize)
|
||||
{
|
||||
if (!dataBrowser)
|
||||
return;
|
||||
auto newSize = view->getViewSize ().getSize ();
|
||||
updateCellSize (newSize);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void MinefieldViewController::updateCellSize (CPoint newSize)
|
||||
{
|
||||
newSize -= {3., 3.};
|
||||
cellSize.x = newSize.x / numCols;
|
||||
cellSize.y = newSize.y / numRows;
|
||||
dataBrowser->recalculateLayout ();
|
||||
font.setSize (cellSize.y / 2.);
|
||||
emojiFont.setSize (cellSize.y / 2.);
|
||||
smallEmojiFont.setSize (font.getSize () / 2.);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "model.h"
|
||||
#include "vstgui/lib/ccolor.h"
|
||||
#include "vstgui/lib/cfont.h"
|
||||
#include "vstgui/lib/idatabrowserdelegate.h"
|
||||
#include "vstgui/lib/iviewlistener.h"
|
||||
#include "vstgui/standalone/include/ivalue.h"
|
||||
#include "vstgui/uidescription/delegationcontroller.h"
|
||||
#include <chrono>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
static constexpr auto maxTimeInSeconds = 999;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class MinefieldViewController : public DelegationController,
|
||||
public DataBrowserDelegateAdapter,
|
||||
public NonAtomicReferenceCounted,
|
||||
public ViewListenerAdapter,
|
||||
public Model::IListener
|
||||
{
|
||||
public:
|
||||
static constexpr auto BombCharacter = "\xF0\x9F\x92\xA3";
|
||||
static constexpr auto FlagCharacter = "\xF0\x9F\x9A\xA9";
|
||||
static constexpr auto ExplosionCharacter = "\xF0\x9F\x92\xA5";
|
||||
static constexpr auto QuestionMarkCharacter = "\xE2\x9D\x93";
|
||||
|
||||
using WonCallbackFunc = std::function<void (int32_t secondsToWin)>;
|
||||
|
||||
MinefieldViewController (IValue& flagsValue, IValue& timeValue, IController* parent,
|
||||
WonCallbackFunc&& wonCallback);
|
||||
|
||||
void startGame (uint32_t rows, uint32_t cols, uint32_t mines);
|
||||
void setMouseMode (bool state);
|
||||
|
||||
private:
|
||||
CView* createView (const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes,
|
||||
const IUIDescription* description) override;
|
||||
void onCellChanged (uint32_t row, uint32_t col) override;
|
||||
int32_t dbGetNumRows (CDataBrowser* browser) override;
|
||||
int32_t dbGetNumColumns (CDataBrowser* browser) override;
|
||||
CCoord dbGetRowHeight (CDataBrowser* browser) override;
|
||||
CCoord dbGetCurrentColumnWidth (int32_t index, CDataBrowser* browser) override;
|
||||
bool dbGetLineWidthAndColor (CCoord& width, CColor& color, CDataBrowser* browser) override;
|
||||
void drawClosedCell (const CRect& r, CDrawContext& context) const;
|
||||
void drawOpenCell (const CRect& r, CDrawContext& context) const;
|
||||
void drawQuestionMark (const CRect& r, CDrawContext& context, CFontRef f) const;
|
||||
void drawQuestionMarkCell (const CRect& r, CDrawContext& context, CFontRef f) const;
|
||||
void drawFlag (const CRect& r, CDrawContext& context, CFontRef f) const;
|
||||
void drawFlaggedCell (const CRect& r, CDrawContext& context, CFontRef f) const;
|
||||
void drawMinedCell (const CRect& r, CDrawContext& context, CFontRef f) const;
|
||||
void drawExplosionCell (const CRect& r, CDrawContext& context, CFontRef f) const;
|
||||
void drawCellNeighbours (const CRect& r, CDrawContext& context, CFontRef f,
|
||||
uint32_t neighbours);
|
||||
void dbDrawCell (CDrawContext* context, const CRect& size, int32_t row, int32_t column,
|
||||
int32_t flags, CDataBrowser* browser) override;
|
||||
CMouseEventResult dbOnMouseDown (const CPoint& where, const CButtonState& buttons, int32_t row,
|
||||
int32_t column, CDataBrowser* browser) override;
|
||||
CMouseEventResult dbOnMouseMoved (const CPoint& where, const CButtonState& buttons, int32_t row,
|
||||
int32_t column, CDataBrowser* browser) override;
|
||||
CMouseEventResult dbOnMouseUp (const CPoint& where, const CButtonState& buttons, int32_t row,
|
||||
int32_t column, CDataBrowser* browser) override;
|
||||
void checkGameOver ();
|
||||
void onGameLost ();
|
||||
void onGameWon ();
|
||||
void onTimer ();
|
||||
void viewSizeChanged (CView* view, const CRect& oldSize) override;
|
||||
void updateCellSize (CPoint newSize);
|
||||
|
||||
private:
|
||||
SharedPointer<CDataBrowser> dataBrowser;
|
||||
SharedPointer<CView> lostView;
|
||||
SharedPointer<CView> wonView;
|
||||
int32_t numRows {1};
|
||||
int32_t numCols {1};
|
||||
std::unique_ptr<Model> model;
|
||||
CColor closedFrameColor {kBlackCColor};
|
||||
CColor closedBackColor {kGreyCColor};
|
||||
CColor openedFrameColor {kGreyCColor};
|
||||
CColor openedBackColor {kTransparentCColor};
|
||||
CColor flagedFrameColor {kGreyCColor};
|
||||
CColor flagedBackColor {kTransparentCColor};
|
||||
CPoint cellSize {30, 30};
|
||||
CFontDesc font {*kSystemFont};
|
||||
CFontDesc smallEmojiFont {*kSymbolFont};
|
||||
CFontDesc emojiFont {*kSymbolFont};
|
||||
IValue& flagsValue;
|
||||
IValue& timeValue;
|
||||
WonCallbackFunc wonCallback;
|
||||
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using TimePoint = std::chrono::time_point<Clock>;
|
||||
TimePoint startTime;
|
||||
SharedPointer<CVSTGUITimer> gameTimer;
|
||||
SharedPointer<CVSTGUITimer> mouseDownTimer;
|
||||
bool ignoreMouseUp {false};
|
||||
bool mouseMode {true};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
+267
@@ -0,0 +1,267 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "model.h"
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <cassert>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
Model::Model (uint32_t numberOfRows, uint32_t numberOfCols, uint32_t numberOfMines,
|
||||
IListener* listener)
|
||||
: mines (numberOfMines), listener (listener)
|
||||
{
|
||||
assert (numberOfMines < numberOfRows * numberOfCols);
|
||||
allocateModel (numberOfRows, numberOfCols);
|
||||
clearModel ();
|
||||
setMines ();
|
||||
calcNeighbours ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
uint32_t Model::getNumberOfMines () const
|
||||
{
|
||||
return mines;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
uint32_t Model::getNumberOfFlags () const
|
||||
{
|
||||
return flagged;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool Model::isTrapped () const
|
||||
{
|
||||
return trapped;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool Model::isDone () const
|
||||
{
|
||||
if (flagged == mines)
|
||||
{
|
||||
for (auto row = 0u; row < matrix.size (); ++row)
|
||||
{
|
||||
for (auto col = 0u; col < matrix.front ().size (); ++col)
|
||||
{
|
||||
auto cell = matrix[row][col];
|
||||
if (cell.isFlag () && !cell.isMine ())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Model::open (uint32_t row, uint32_t col)
|
||||
{
|
||||
if (openInternal (row, col))
|
||||
{
|
||||
auto cell = matrix[row][col];
|
||||
if (cell.isOpen () && cell.neighbours == 0)
|
||||
{
|
||||
openCleanNearby (row, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Model::mark (uint32_t row, uint32_t col)
|
||||
{
|
||||
auto& cell = matrix[row][col];
|
||||
if (cell.isFlag ())
|
||||
{
|
||||
--flagged;
|
||||
cell.unsetFlag ();
|
||||
cell.setQuestion ();
|
||||
}
|
||||
else if (cell.isQuestion ())
|
||||
{
|
||||
cell.unsetQuestion ();
|
||||
}
|
||||
else
|
||||
{
|
||||
++flagged;
|
||||
cell.setFlag ();
|
||||
}
|
||||
if (listener)
|
||||
listener->onCellChanged (row, col);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool Model::isOpen (uint32_t row, uint32_t col) const
|
||||
{
|
||||
return matrix[row][col].isOpen ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool Model::isFlag (uint32_t row, uint32_t col) const
|
||||
{
|
||||
return matrix[row][col].isFlag ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool Model::isQuestion (uint32_t row, uint32_t col) const
|
||||
{
|
||||
return matrix[row][col].isQuestion ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool Model::isMine (uint32_t row, uint32_t col) const
|
||||
{
|
||||
return matrix[row][col].isMine ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool Model::isTrapMine (uint32_t row, uint32_t col) const
|
||||
{
|
||||
return matrix[row][col].isTrap ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
uint32_t Model::getNumberOfMinesNearby (uint32_t row, uint32_t col) const
|
||||
{
|
||||
return matrix[row][col].neighbours;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Model::openCleanNearby (uint32_t row, uint32_t col)
|
||||
{
|
||||
const auto maxCol = matrix.front ().size () - 1;
|
||||
const auto maxRow = matrix.size () - 1;
|
||||
if (row > 0)
|
||||
{
|
||||
if (col > 0)
|
||||
open (row - 1, col - 1);
|
||||
open (row - 1, col);
|
||||
if (col < maxCol)
|
||||
open (row - 1, col + 1);
|
||||
}
|
||||
if (col > 0)
|
||||
open (row, col - 1);
|
||||
if (col < maxCol)
|
||||
open (row, col + 1);
|
||||
if (row < maxRow)
|
||||
{
|
||||
if (col > 0)
|
||||
open (row + 1, col - 1);
|
||||
open (row + 1, col);
|
||||
if (col < maxCol)
|
||||
open (row + 1, col + 1);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool Model::openInternal (uint32_t row, uint32_t col)
|
||||
{
|
||||
auto& cell = matrix[row][col];
|
||||
if (!cell.isOpen ())
|
||||
{
|
||||
cell.setOpen ();
|
||||
++opened;
|
||||
if (cell.isFlag ())
|
||||
{
|
||||
cell.unsetFlag ();
|
||||
--flagged;
|
||||
}
|
||||
else if (cell.isQuestion ())
|
||||
cell.unsetQuestion ();
|
||||
if (listener)
|
||||
listener->onCellChanged (row, col);
|
||||
if (cell.isMine ())
|
||||
{
|
||||
cell.setTrap ();
|
||||
trapped = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Model::allocateModel (uint32_t numberOfRows, uint32_t numberOfCols)
|
||||
{
|
||||
matrix.resize (numberOfRows);
|
||||
std::for_each (matrix.begin (), matrix.end (),
|
||||
[numberOfCols] (auto& r) { r.resize (numberOfCols); });
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Model::clearModel ()
|
||||
{
|
||||
std::for_each (matrix.begin (), matrix.end (), [] (auto& r) {
|
||||
std::for_each (r.begin (), r.end (), [] (auto& cell) { cell = {}; });
|
||||
});
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Model::setMines ()
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen (rd ());
|
||||
std::uniform_int_distribution<> rowDist (0, static_cast<int> (matrix.size () - 1));
|
||||
std::uniform_int_distribution<> colDist (0, static_cast<int> (matrix.front ().size () - 1));
|
||||
for (auto i = 0u; i < mines; ++i)
|
||||
{
|
||||
auto row = rowDist (gen);
|
||||
auto col = colDist (gen);
|
||||
if ((matrix[row][col]).isMine ())
|
||||
{
|
||||
assert (i > 0u);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
matrix[row][col].setMine ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void Model::calcNeighbours ()
|
||||
{
|
||||
const auto maxCol = matrix.front ().size () - 1;
|
||||
const auto maxRow = matrix.size () - 1;
|
||||
for (auto row = 0u; row < matrix.size (); ++row)
|
||||
{
|
||||
for (auto col = 0u; col < matrix.front ().size (); ++col)
|
||||
{
|
||||
auto& cell = matrix[row][col];
|
||||
if (cell.isMine ())
|
||||
continue;
|
||||
if (row > 0)
|
||||
{
|
||||
if (col > 0)
|
||||
cell.neighbours += matrix[row - 1][col - 1].isMine () ? 1 : 0;
|
||||
cell.neighbours += matrix[row - 1][col].isMine () ? 1 : 0;
|
||||
if (col < maxCol)
|
||||
cell.neighbours += matrix[row - 1][col + 1].isMine () ? 1 : 0;
|
||||
}
|
||||
if (col > 0)
|
||||
cell.neighbours += matrix[row][col - 1].isMine () ? 1 : 0;
|
||||
if (col < maxCol)
|
||||
cell.neighbours += matrix[row][col + 1].isMine () ? 1 : 0;
|
||||
if (row < maxRow)
|
||||
{
|
||||
if (col > 0)
|
||||
cell.neighbours += matrix[row + 1][col - 1].isMine () ? 1 : 0;
|
||||
cell.neighbours += matrix[row + 1][col].isMine () ? 1 : 0;
|
||||
if (col < maxCol)
|
||||
cell.neighbours += matrix[row + 1][col + 1].isMine () ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class Model
|
||||
{
|
||||
private:
|
||||
enum class Bit : uint16_t
|
||||
{
|
||||
Mine = 1 << 0,
|
||||
Open = 1 << 1,
|
||||
Flag = 1 << 2,
|
||||
Trap = 1 << 3,
|
||||
Question = 1 << 4,
|
||||
};
|
||||
|
||||
static bool hasBit (uint16_t s, Bit flag) { return (s & static_cast<uint16_t> (flag)) != 0; }
|
||||
static void setBit (uint16_t& s, Bit flag) { s |= static_cast<uint16_t> (flag); }
|
||||
static void unsetBit (uint16_t& s, Bit flag) { s &= ~static_cast<uint16_t> (flag); }
|
||||
|
||||
struct Cell
|
||||
{
|
||||
uint16_t neighbours {0};
|
||||
uint16_t flags {0};
|
||||
|
||||
bool isMine () const { return hasBit (flags, Bit::Mine); }
|
||||
bool isOpen () const { return hasBit (flags, Bit::Open); }
|
||||
bool isFlag () const { return hasBit (flags, Bit::Flag); }
|
||||
bool isTrap () const { return hasBit (flags, Bit::Trap); }
|
||||
bool isQuestion () const { return hasBit (flags, Bit::Question); }
|
||||
|
||||
void setMine () { setBit (flags, Bit::Mine); }
|
||||
void setOpen () { setBit (flags, Bit::Open); }
|
||||
void setTrap () { setBit (flags, Bit::Trap); }
|
||||
void setFlag () { setBit (flags, Bit::Flag); }
|
||||
void unsetFlag () { unsetBit (flags, Bit::Flag); }
|
||||
void setQuestion () { setBit (flags, Bit::Question); }
|
||||
void unsetQuestion () { unsetBit (flags, Bit::Question); }
|
||||
};
|
||||
|
||||
using Row = std::vector<Cell>;
|
||||
using Matrix = std::vector<Row>;
|
||||
|
||||
public:
|
||||
struct IListener
|
||||
{
|
||||
virtual void onCellChanged (uint32_t row, uint32_t col) = 0;
|
||||
};
|
||||
|
||||
Model (uint32_t numberOfRows, uint32_t numberOfCols, uint32_t numberOfMines,
|
||||
IListener* listener);
|
||||
|
||||
uint32_t getNumberOfMines () const;
|
||||
uint32_t getNumberOfFlags () const;
|
||||
|
||||
void open (uint32_t row, uint32_t col);
|
||||
void mark (uint32_t row, uint32_t col);
|
||||
|
||||
bool isTrapped () const;
|
||||
bool isDone () const;
|
||||
bool isOpen (uint32_t row, uint32_t col) const;
|
||||
bool isFlag (uint32_t row, uint32_t col) const;
|
||||
bool isQuestion (uint32_t row, uint32_t col) const;
|
||||
bool isMine (uint32_t row, uint32_t col) const;
|
||||
bool isTrapMine (uint32_t row, uint32_t col) const;
|
||||
uint32_t getNumberOfMinesNearby (uint32_t row, uint32_t col) const;
|
||||
|
||||
private:
|
||||
void openCleanNearby (uint32_t row, uint32_t col);
|
||||
bool openInternal (uint32_t row, uint32_t col);
|
||||
void allocateModel (uint32_t numberOfRows, uint32_t numberOfCols);
|
||||
void clearModel ();
|
||||
void setMines ();
|
||||
void calcNeighbours ();
|
||||
|
||||
Matrix matrix;
|
||||
uint32_t mines {0};
|
||||
uint32_t opened {0};
|
||||
uint32_t flagged {0};
|
||||
bool trapped {false};
|
||||
IListener* listener {nullptr};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "commands.h"
|
||||
#include "windowcontroller.h"
|
||||
#include "vstgui/standalone/include/helpers/appdelegate.h"
|
||||
#include "vstgui/standalone/include/helpers/menubuilder.h"
|
||||
#include "vstgui/standalone/include/helpers/windowlistener.h"
|
||||
#include "vstgui/standalone/include/iapplication.h"
|
||||
#include "vstgui/standalone/include/iuidescwindow.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class MyApplication final : public Application::DelegateAdapter,
|
||||
public WindowListenerAdapter,
|
||||
public MenuBuilderAdapter
|
||||
{
|
||||
public:
|
||||
MyApplication ()
|
||||
: Application::DelegateAdapter ({"Minesweeper", "1.0.0", VSTGUI_STANDALONE_APP_URI})
|
||||
{
|
||||
}
|
||||
|
||||
void finishLaunching () override
|
||||
{
|
||||
auto windowController = std::make_shared<WindowController> ();
|
||||
UIDesc::Config config;
|
||||
config.uiDescFileName = "Window.uidesc";
|
||||
config.viewName = "Window";
|
||||
config.customization = windowController;
|
||||
config.modelBinding = windowController;
|
||||
config.windowConfig.title = "Minesweeper";
|
||||
config.windowConfig.autoSaveFrameName = "MinesweeperWindow";
|
||||
config.windowConfig.style.border ().close ().centered ().size ();
|
||||
if (auto window = UIDesc::makeWindow (config))
|
||||
{
|
||||
window->show ();
|
||||
window->registerWindowListener (this);
|
||||
}
|
||||
else
|
||||
{
|
||||
IApplication::instance ().quit ();
|
||||
}
|
||||
}
|
||||
void onClosed (const IWindow& window) override { IApplication::instance ().quit (); }
|
||||
|
||||
SortFunction getCommandGroupSortFunction (const Interface& context,
|
||||
const UTF8String& group) const override
|
||||
{
|
||||
if (group == GameGroup)
|
||||
{
|
||||
return [] (const UTF8String& lhs, const UTF8String& rhs) {
|
||||
static const auto order = {NewGameCommand.name,
|
||||
NewBeginnerGameCommand.name,
|
||||
NewIntermediateGameCommand.name,
|
||||
NewExpertGameCommand.name,
|
||||
MouseModeCommand.name,
|
||||
TouchpadModeCommand.name,
|
||||
ToggleHighscoresCommand.name};
|
||||
auto leftIndex = std::find (order.begin (), order.end (), lhs);
|
||||
auto rightIndex = std::find (order.begin (), order.end (), rhs);
|
||||
return std::distance (leftIndex, rightIndex) > 0;
|
||||
};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool prependMenuSeparator (const Interface& context, const Command& cmd) const override
|
||||
{
|
||||
if (cmd == Commands::CloseWindow || cmd == MouseModeCommand || cmd == ToggleHighscoresCommand)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static Application::Init gAppDelegate (std::make_unique<MyApplication> ());
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
Vendored
+467
@@ -0,0 +1,467 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "commands.h"
|
||||
#include "highscores.h"
|
||||
#include "highscoreviewcontroller.h"
|
||||
#include "keepchildviewscentered.h"
|
||||
#include "minefieldviewcontroller.h"
|
||||
#include "vstgui/standalone/include/helpers/preferences.h"
|
||||
#include "vstgui/standalone/include/helpers/value.h"
|
||||
#include "vstgui/standalone/include/iapplication.h"
|
||||
#include "vstgui/uidescription/delegationcontroller.h"
|
||||
#include "vstgui/uidescription/iuidescription.h"
|
||||
#include "vstgui/uidescription/uiattributes.h"
|
||||
#include "windowcontroller.h"
|
||||
#include <cassert>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class EnterHighScoreViewController final : public DelegationController,
|
||||
public ValueListenerAdapter,
|
||||
public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
using OnEndEditFunc = std::function<void ()>;
|
||||
|
||||
EnterHighScoreViewController (IValue& nameValue, IValue& okValue, IController* parent,
|
||||
OnEndEditFunc&& func)
|
||||
: DelegationController (parent)
|
||||
, nameValue (nameValue)
|
||||
, okValue (okValue)
|
||||
, onEndEditFunc (std::move (func))
|
||||
{
|
||||
okValue.registerListener (this);
|
||||
okValue.setActive (false);
|
||||
}
|
||||
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes,
|
||||
const IUIDescription* description) override
|
||||
{
|
||||
const auto attr = attributes.getAttributeValue (IUIDescription::kCustomViewName);
|
||||
if (attr)
|
||||
{
|
||||
if (*attr == "MainView")
|
||||
{
|
||||
mainView = view;
|
||||
mainView->setAlphaValue (0.f);
|
||||
mainView->setMouseEnabled (false);
|
||||
keepChildViewsCentered (mainView->asViewContainer ());
|
||||
}
|
||||
}
|
||||
|
||||
return DelegationController::verifyView (view, attributes, description);
|
||||
}
|
||||
|
||||
void onNewHighscore (uint32_t secondsToWin, const std::shared_ptr<HighScoreList>& list)
|
||||
{
|
||||
currentSecondsToWin = secondsToWin;
|
||||
highscoreList = list;
|
||||
mainView->setAlphaValue (1.f);
|
||||
mainView->setMouseEnabled (true);
|
||||
okValue.setActive (true);
|
||||
}
|
||||
|
||||
void onEndEdit (IValue& value) override
|
||||
{
|
||||
if (value.getValue () > 0.5)
|
||||
{
|
||||
value.performEdit (0.);
|
||||
auto name = Value::currentStringValue (nameValue);
|
||||
highscoreList->addHighscore (name, currentSecondsToWin);
|
||||
highscoreList = nullptr;
|
||||
mainView->setMouseEnabled (false);
|
||||
mainView->setAlphaValue (0.f);
|
||||
onEndEditFunc ();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SharedPointer<CView> mainView;
|
||||
IValue& nameValue;
|
||||
IValue& okValue;
|
||||
std::shared_ptr<HighScoreList> highscoreList;
|
||||
uint32_t currentSecondsToWin {0};
|
||||
OnEndEditFunc onEndEditFunc;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class DigitsDisplayConverter final : public IValueConverter
|
||||
{
|
||||
public:
|
||||
DigitsDisplayConverter (ValueConverterPtr converter, uint32_t digits)
|
||||
: converter (converter), digits (digits)
|
||||
{
|
||||
}
|
||||
|
||||
UTF8String valueAsString (IValue::Type value) const override
|
||||
{
|
||||
auto plain = static_cast<uint32_t> (std::round (converter->normalizedToPlain (value)));
|
||||
UTF8String str;
|
||||
auto val = static_cast<uint32_t> (std::pow (10, digits - 1));
|
||||
for (auto i = digits; i > 0; --i)
|
||||
{
|
||||
auto v = plain / val;
|
||||
str += toString (v);
|
||||
plain -= v * val;
|
||||
val /= 10;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
IValue::Type stringAsValue (const UTF8String& string) const override
|
||||
{
|
||||
return converter->stringAsValue (string);
|
||||
}
|
||||
IValue::Type plainToNormalized (IValue::Type plain) const override
|
||||
{
|
||||
return converter->plainToNormalized (plain);
|
||||
}
|
||||
IValue::Type normalizedToPlain (IValue::Type normalized) const override
|
||||
{
|
||||
return converter->normalizedToPlain (normalized);
|
||||
}
|
||||
|
||||
private:
|
||||
ValueConverterPtr converter;
|
||||
uint32_t digits {3};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static constexpr auto valueRows = "Rows";
|
||||
static constexpr auto valueCols = "Cols";
|
||||
static constexpr auto valueMines = "Mines";
|
||||
static constexpr auto valueStart = "Start";
|
||||
static constexpr auto valueFlags = "Flags";
|
||||
static constexpr auto valueTime = "Time";
|
||||
static constexpr auto valueMouseMode = "MouseMode";
|
||||
static constexpr auto valueNewHighScoreOK = "NewHighScoreOK";
|
||||
static constexpr auto valueNewHighScoreName = "NewHighScoreName";
|
||||
static constexpr auto valueCloseHighscoreView = "CloseHighscoreView";
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
WindowController::WindowController ()
|
||||
{
|
||||
IApplication::instance ().registerCommand (NewGameCommand, 'n');
|
||||
IApplication::instance ().registerCommand (NewBeginnerGameCommand, '1');
|
||||
IApplication::instance ().registerCommand (NewIntermediateGameCommand, '2');
|
||||
IApplication::instance ().registerCommand (NewExpertGameCommand, '3');
|
||||
IApplication::instance ().registerCommand (MouseModeCommand, 0);
|
||||
IApplication::instance ().registerCommand (TouchpadModeCommand, 0);
|
||||
IApplication::instance ().registerCommand (ToggleHighscoresCommand, '/');
|
||||
|
||||
addCreateViewControllerFunc (
|
||||
"MinefieldController", [this] (const auto& name, auto* parent, auto* uidesc) {
|
||||
if (!minefieldViewController)
|
||||
{
|
||||
auto flagsValue = modelBinding.getValue (valueFlags);
|
||||
auto timeValue = modelBinding.getValue (valueTime);
|
||||
minefieldViewController = owned (new MinefieldViewController (
|
||||
*flagsValue, *timeValue, parent,
|
||||
[this] (uint32_t secondsToWin) { onWon (secondsToWin); }));
|
||||
if (auto valueObject = modelBinding.getValue (valueMouseMode))
|
||||
{
|
||||
minefieldViewController->setMouseMode (valueObject->getValue () >= 0.5 ? true :
|
||||
false);
|
||||
}
|
||||
}
|
||||
minefieldViewController->remember ();
|
||||
return minefieldViewController;
|
||||
});
|
||||
|
||||
addCreateViewControllerFunc (
|
||||
"NewHighScoreViewController", [this] (const auto& name, auto* parent, auto* uidesc) {
|
||||
if (!enterHighscoreViewController)
|
||||
{
|
||||
auto nameValue = modelBinding.getValue (valueNewHighScoreName);
|
||||
auto okValue = modelBinding.getValue (valueNewHighScoreOK);
|
||||
enterHighscoreViewController = owned (new EnterHighScoreViewController (
|
||||
*nameValue, *okValue, parent, [this] () { showHighscores (); }));
|
||||
}
|
||||
enterHighscoreViewController->remember ();
|
||||
return enterHighscoreViewController;
|
||||
});
|
||||
|
||||
addCreateViewControllerFunc (
|
||||
"HighScoreViewController", [this] (const auto& name, auto* parent, auto* uidesc) {
|
||||
if (!highscoreViewController)
|
||||
highscoreViewController = owned (new HighScoreViewController (parent));
|
||||
highscoreViewController->remember ();
|
||||
return highscoreViewController;
|
||||
});
|
||||
|
||||
modelBinding.addValue (
|
||||
Value::make (valueRows, 0, Value::makeRangeConverter (8, 30, 0)),
|
||||
UIDesc::ValueCalls::onEndEdit ([this] (auto& value) { verifyNumMines (); }));
|
||||
modelBinding.addValue (
|
||||
Value::make (valueCols, 0, Value::makeRangeConverter (8, 30, 0)),
|
||||
UIDesc::ValueCalls::onEndEdit ([this] (auto& value) { verifyNumMines (); }));
|
||||
modelBinding.addValue (
|
||||
Value::make (valueMines, 0, Value::makeRangeConverter (4, 668, 0)),
|
||||
UIDesc::ValueCalls::onEndEdit ([this] (auto& value) { verifyNumMines (); }));
|
||||
modelBinding.addValue (Value::make (
|
||||
valueFlags, 0,
|
||||
std::make_shared<DigitsDisplayConverter> (Value::makeRangeConverter (0, 668, 0), 2)));
|
||||
modelBinding.addValue (
|
||||
Value::make (valueTime, 0,
|
||||
std::make_shared<DigitsDisplayConverter> (
|
||||
Value::makeRangeConverter (0, maxTimeInSeconds, 0), 3)));
|
||||
if (auto value = modelBinding.getValue (valueMines))
|
||||
Value::performSinglePlainEdit (*value.get (), 10);
|
||||
modelBinding.addValue (
|
||||
Value::make (valueStart),
|
||||
UIDesc::ValueCalls::onEndEdit ([this] (auto& value) { startNewGame (); }));
|
||||
modelBinding.addValue (
|
||||
Value::make (valueMouseMode), UIDesc::ValueCalls::onPerformEdit ([this] (auto& value) {
|
||||
if (minefieldViewController)
|
||||
minefieldViewController->setMouseMode (value.getValue () >= 0.5 ? true : false);
|
||||
}));
|
||||
|
||||
modelBinding.addValue (Value::makeStringValue (valueNewHighScoreName, ""));
|
||||
modelBinding.addValue (Value::make (valueNewHighScoreOK));
|
||||
|
||||
modelBinding.addValue (Value::make (valueCloseHighscoreView),
|
||||
UIDesc::ValueCalls::onPerformEdit ([this] (auto& value) {
|
||||
if (value.getValue () >= 0.5)
|
||||
{
|
||||
value.performEdit (0.);
|
||||
hideHighscores ();
|
||||
}
|
||||
}));
|
||||
|
||||
loadDefaults ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
WindowController::~WindowController () noexcept = default;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void WindowController::loadDefaults ()
|
||||
{
|
||||
Preferences prefs ("Values");
|
||||
if (auto value = prefs.getNumber<int32_t> (valueRows))
|
||||
{
|
||||
if (auto valueObject = modelBinding.getValue (valueRows))
|
||||
Value::performSinglePlainEdit (*valueObject, *value);
|
||||
}
|
||||
if (auto value = prefs.getNumber<int32_t> (valueCols))
|
||||
{
|
||||
if (auto valueObject = modelBinding.getValue (valueCols))
|
||||
Value::performSinglePlainEdit (*valueObject, *value);
|
||||
}
|
||||
if (auto value = prefs.getNumber<int32_t> (valueMines))
|
||||
{
|
||||
if (auto valueObject = modelBinding.getValue (valueMines))
|
||||
Value::performSinglePlainEdit (*valueObject, *value);
|
||||
}
|
||||
if (auto value = prefs.getNumber<bool> (valueMouseMode))
|
||||
{
|
||||
if (auto valueObject = modelBinding.getValue (valueMouseMode))
|
||||
Value::performSinglePlainEdit (*valueObject, *value);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void WindowController::storeDefaults ()
|
||||
{
|
||||
Preferences prefs ("Values");
|
||||
if (auto value = modelBinding.getValue (valueRows))
|
||||
prefs.setNumber (valueRows, static_cast<int32_t> (Value::currentPlainValue (*value)));
|
||||
if (auto value = modelBinding.getValue (valueCols))
|
||||
prefs.setNumber (valueCols, static_cast<int32_t> (Value::currentPlainValue (*value)));
|
||||
if (auto value = modelBinding.getValue (valueMines))
|
||||
prefs.setNumber (valueMines, static_cast<int32_t> (Value::currentPlainValue (*value)));
|
||||
if (auto value = modelBinding.getValue (valueMouseMode))
|
||||
prefs.setNumber (valueMouseMode, static_cast<bool> (Value::currentPlainValue (*value)));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool WindowController::canHandleCommand (const Command& command)
|
||||
{
|
||||
if (command.group == GameGroup)
|
||||
{
|
||||
if (command.name == TouchpadMode)
|
||||
{
|
||||
if (modelBinding.getValue (valueMouseMode)->getValue () < 0.5)
|
||||
return false;
|
||||
}
|
||||
if (command.name == MouseMode)
|
||||
{
|
||||
if (modelBinding.getValue (valueMouseMode)->getValue () >= 0.5)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool WindowController::handleCommand (const Command& command)
|
||||
{
|
||||
if (command.group != GameGroup)
|
||||
return false;
|
||||
if (command.name == ToggleHighscores)
|
||||
{
|
||||
showHideHighscores ();
|
||||
return true;
|
||||
}
|
||||
if (command.name == TouchpadMode)
|
||||
{
|
||||
auto value = modelBinding.getValue (valueMouseMode);
|
||||
Value::performSingleEdit (*value, 0.);
|
||||
return true;
|
||||
}
|
||||
else if (command.name == MouseMode)
|
||||
{
|
||||
auto value = modelBinding.getValue (valueMouseMode);
|
||||
Value::performSingleEdit (*value, 1.);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto rowValue = modelBinding.getValue (valueRows);
|
||||
auto colValue = modelBinding.getValue (valueCols);
|
||||
auto mineValue = modelBinding.getValue (valueMines);
|
||||
if (!rowValue || !colValue || !mineValue)
|
||||
return false;
|
||||
if (command == NewBeginnerGameCommand)
|
||||
{
|
||||
Value::performSinglePlainEdit (*rowValue, 9);
|
||||
Value::performSinglePlainEdit (*colValue, 9);
|
||||
Value::performSinglePlainEdit (*mineValue, 10);
|
||||
}
|
||||
else if (command == NewIntermediateGameCommand)
|
||||
{
|
||||
Value::performSinglePlainEdit (*rowValue, 16);
|
||||
Value::performSinglePlainEdit (*colValue, 16);
|
||||
Value::performSinglePlainEdit (*mineValue, 40);
|
||||
}
|
||||
else if (command == NewExpertGameCommand)
|
||||
{
|
||||
Value::performSinglePlainEdit (*rowValue, 16);
|
||||
Value::performSinglePlainEdit (*colValue, 30);
|
||||
Value::performSinglePlainEdit (*mineValue, 99);
|
||||
}
|
||||
else
|
||||
{
|
||||
hideHighscores ();
|
||||
}
|
||||
|
||||
startNewGame ();
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void WindowController::beforeShow (IWindow& w)
|
||||
{
|
||||
window = &w;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void WindowController::onShow (const IWindow& w)
|
||||
{
|
||||
startNewGame ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void WindowController::onClosed (const IWindow& w)
|
||||
{
|
||||
storeDefaults ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
auto WindowController::getValues () const -> const ValueList&
|
||||
{
|
||||
return modelBinding.getValues ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
std::tuple<uint32_t, uint32_t, uint32_t> WindowController::getRowsColsMines ()
|
||||
{
|
||||
auto rows =
|
||||
static_cast<uint32_t> (Value::currentPlainValue (*modelBinding.getValue (valueRows)));
|
||||
auto cols =
|
||||
static_cast<uint32_t> (Value::currentPlainValue (*modelBinding.getValue (valueCols)));
|
||||
auto mines =
|
||||
static_cast<uint32_t> (Value::currentPlainValue (*modelBinding.getValue (valueMines)));
|
||||
return {rows, cols, mines};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void WindowController::startNewGame ()
|
||||
{
|
||||
assert (minefieldViewController);
|
||||
uint32_t rows, cols, mines;
|
||||
std::tie (rows, cols, mines) = getRowsColsMines ();
|
||||
minefieldViewController->startGame (rows, cols, mines);
|
||||
auto highscoreList = HighScores::instance ().get (rows, cols, mines);
|
||||
if (!highscoreList)
|
||||
return;
|
||||
highscoreViewController->setHighScoreList (highscoreList);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void WindowController::verifyNumMines ()
|
||||
{
|
||||
uint32_t rows, cols, mines;
|
||||
std::tie (rows, cols, mines) = getRowsColsMines ();
|
||||
if (rows * cols < mines)
|
||||
{
|
||||
Value::performSinglePlainEdit (*modelBinding.getValue (valueMines), rows * cols * 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void WindowController::onWon (uint32_t secondsToWin)
|
||||
{
|
||||
uint32_t rows, cols, mines;
|
||||
std::tie (rows, cols, mines) = getRowsColsMines ();
|
||||
auto highscoreList = HighScores::instance ().get (rows, cols, mines);
|
||||
if (!highscoreList)
|
||||
return;
|
||||
|
||||
auto pos = highscoreList->isHighScore (secondsToWin);
|
||||
if (pos)
|
||||
{
|
||||
enterHighscoreViewController->onNewHighscore (secondsToWin, highscoreList);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void WindowController::showHideHighscores ()
|
||||
{
|
||||
if (!highscoreViewController)
|
||||
return;
|
||||
if (highscoreViewController->isVisible ())
|
||||
highscoreViewController->hide ();
|
||||
else
|
||||
showHighscores ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void WindowController::showHighscores ()
|
||||
{
|
||||
assert (highscoreViewController);
|
||||
uint32_t rows, cols, mines;
|
||||
std::tie (rows, cols, mines) = getRowsColsMines ();
|
||||
if (auto highscoreList = HighScores::instance ().get (rows, cols, mines))
|
||||
{
|
||||
highscoreViewController->setHighScoreList (highscoreList);
|
||||
highscoreViewController->show ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void WindowController::hideHighscores ()
|
||||
{
|
||||
assert (highscoreViewController);
|
||||
highscoreViewController->hide ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
Vendored
+62
@@ -0,0 +1,62 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vstgui/standalone/include/helpers/uidesc/customization.h"
|
||||
#include "vstgui/standalone/include/helpers/uidesc/modelbinding.h"
|
||||
#include "vstgui/standalone/include/helpers/windowcontroller.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
namespace Standalone {
|
||||
namespace Minesweeper {
|
||||
|
||||
class MinefieldViewController;
|
||||
class EnterHighScoreViewController;
|
||||
class HighScoreViewController;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class WindowController final : public WindowControllerAdapter,
|
||||
public UIDesc::Customization,
|
||||
public UIDesc::IModelBinding,
|
||||
public ICommandHandler
|
||||
{
|
||||
public:
|
||||
WindowController ();
|
||||
~WindowController () noexcept override;
|
||||
|
||||
void loadDefaults ();
|
||||
void storeDefaults ();
|
||||
|
||||
bool canHandleCommand (const Command& command) override;
|
||||
bool handleCommand (const Command& command) override;
|
||||
|
||||
void beforeShow (IWindow& w) override;
|
||||
void onShow (const IWindow& w) override;
|
||||
void onClosed (const IWindow& w) override;
|
||||
|
||||
const ValueList& getValues () const override;
|
||||
|
||||
std::tuple<uint32_t, uint32_t, uint32_t> getRowsColsMines ();
|
||||
void startNewGame ();
|
||||
void verifyNumMines ();
|
||||
void onWon (uint32_t secondsToWin);
|
||||
|
||||
private:
|
||||
void showHideHighscores ();
|
||||
void showHighscores ();
|
||||
void hideHighscores ();
|
||||
|
||||
UIDesc::ModelBindingCallbacks modelBinding;
|
||||
SharedPointer<MinefieldViewController> minefieldViewController;
|
||||
SharedPointer<EnterHighScoreViewController> enterHighscoreViewController;
|
||||
SharedPointer<HighScoreViewController> highscoreViewController;
|
||||
IWindow* window {nullptr};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Minesweeper
|
||||
} // Standalone
|
||||
} // VSTGUI
|
||||
Reference in New Issue
Block a user