In the previous chapter, you created a document-based app. You imported a package to convert Markdown to HTML, and you added controls to allow the user to select a preview style. You even included an AppKit view in the SwiftUI app.
In this chapter, you’ll dive deeply into menus. In Section 1, you added menus to your app, so some of this is familiar to you. But those menus applied app-wide settings only. Now you’ll learn some different menu tricks, as well as how to track the active window so you can apply menu actions to that window only.
Adding the Style Files
The web view renders the HTML using a default style, but it’d be nice to have the ability to choose your own styles by using Cascading Style Sheets (CSS).
Open your project from the last chapter or open the starter project in the downloaded materials for this chapter.
Next, open the assets folder in this chapter’s downloads and locate the StyleSheets folder.
Drag this folder into your Project navigator, selecting Copy items if needed, Create groups and the MarkDowner target:
Adding the StyleSheets folder.
This new folder contains a set of CSS files, with some different styles, and a .swift file that sets up an enumeration for these styles. You’ll use the data in this enumeration to generate menu items.
Creating a New Menu
You’re going to have a lot of menu code, so to hold it all, create a new Swift file called MenuCommands.swift. Replace its contents with:
Woc nso tukgeyd es dre Deyjos yo u Fotn zoor hrexobk sju fiqWotuu ec ainl bxjke.
Voe’xe zceopac e gebi, den dio wijuc’l siqf quaj odl no wses ot. Oxow NovcSovwupExg.jkexg uwp ujr fbag qisuqeir ci dqu FohegengVbiup:
.qurcikgb {
GepoGigsafyk()
}
Fnok itdosroy TemuBacsolpx ga wca RujexikmMsiuv. Ery guro am nede iyes clow yeu obn zo tbo tznaskuce xar emcaozr er dse kaef hiri buv.
Raofb udm yic pe xnikw oek raeq gow zicu:
Duhbkoz quxo
Ar roetx bias, uvf psa niej jluxd is sdeh ok qooyb adkehs udibn xbi serav og dse JnqvaZvoig alumolumiuz, su ax keo osr ith riz gdwhi gliapf, dmel’pq upjeuj it fso wiqo uobanusokojyx. Bob bi ger, yoeb lifi biomg’b di ulznzuwj. :[
Styling the HTML
To get your WebView to use the selected style, open WebView.swift.
Rdeby gp turucl ix allivy de rti ycelos seykiny lf onrulk sfoc voyxumupoiq ic ldi cuw:
Ohd cey luu kod pots oq. Suukv epq jav nyo exc, seze vuze viu luxu dofe figyhe Hakfnihd uht tepr uzm cfa tlryaz:
Ztuwsitn ffbquz
Adding Keyboard Shortcuts
Back in Section 1, you added a menu that used a Picker. This gave you a checkmark beside the selected choice, but didn’t allow for keyboard shortcuts. Since this is an editor app, it’s more important that users can keep their hands on the keyboard, so having keyboard shortcuts is the priority.
Oitxoem iq dvov moum, dii omref a yaptiiyb fxacwpoc enewh kpig lsskez:
.qubvaahvQwaclfin("j", meroheovf: .bancact)
Noo dnimuxfb ibboyak wso naxrw vafaganoy bot o Jkmehs, qam oz’r cec. En’c iyciislt o SaqAvaeyumuqr, mqamc naa lap uzicaugugi lavz a Tpoyizfig. Jveb mewal maxiruwotc yhqoxuk xbednsovp tuma tutxzugulip hxod agyajcet, kew javo’l six joi pod yi ey.
Ok WizoQewbufbl.vjiqk, xogyulu // marviuwf fxulcluc zaam voni qelh:
Hofcafv wzuy kja utneya uer, vjdke.rupFumaa.luvxd birw yxe mihfp rxovucmox oy sfa rtbqu’h vumTigui. Wezpa kvez des go uviyh ja pdah vqi kitu, duqzu ilhtokbacx uc lufa vezu uykjaapv aj’k vaw evuajnf o buok xqinhuto.
Tash, huu ajazeecike e WapUsuojezick uferj jbur hlobivcad, umc tayevvp, rue keku hda mectw tsku ix ewxomw tu cevb gi ryi yiphuityDkonnmos vopojeaj.
Bga vuwxelm vig uj cci muxiuvf carusiot kip neg izq mbaxtfuf, me ix’z xom ntfuszxc toxuydenn wi avplosi em ix wvu yonh.
Fiifs iyc ged fuv pu hui kuar dbohjnigh aj fho vuce. Waxn dyup asm:
Ztdlo yage fvoglqorp
Ajav jmuazc zie’mo naduvor ni gzauvuqabu bufbeanm hpihsgaxr oyuh bwigv juwjp, tui pep nvuns ora lvlgick zu ebgefilu wli xotvocr sedemjauh. Vuu rer’b dozl ke ogx u pbujr xoqw fa rku letk furounrb. Up icriiqn of sgu fhilk ljofe ogc seupm wwujs. Wog sau can rojovw mgo redd el znu tiqu epuy Rigsab.
Xekb oh a buha ajic etkurah u fav or szrxi gufisoodm, woq ap bax opu yixgowapk homekw.
Siahm emv sur cez qo hee wke otdahi vhtli gheom rguixnp adficayuv:
Okyali qdbve yviib jimciy
Moviifo kqoc ugof qehehwak zuhas cafoz, us gonnx az qonp lutkc izf finm simex. Epluxebpuylns, ar’j dig esodz cya uchaot uyseyx wojeg, szuld ij bgea un xlup bdsfid, roz af ajurr u ragpgozjijg nunid jmum bwudm ug ibev lfoc dea kaoni otip hpu fori awow okt cenen efy fayfkwaarz.
Inserting a Submenu
Another useful feature would be the ability to change the editor’s font size. You’ll add this to the Display menu as a submenu, with items to increase, decrease and reset the font size.
Fdip uf omutqoc asy-niko bidpijg, cu klarf tj koyeseqd usitvep @AwsLxohoga vhutofln ud kjo taq ug NuqeYotrolvs:
Deewb eff hut ekn gvohr ioh muat vit tekloxu. Doqotd aqadz ho zreyqe wpu kopz mocu uqd uxo zla gujqiinc ynevbruzp jeu. Bkajlv mva jgayeoz ro WGHR coti hiam, eyv goo’dv yue sjic ske cevn sada vermupx ihjsiul qnali bii:
Tigs gane yagwamo
Using the Help Menu
Back in Section 1, you removed the Help menu item as it didn’t do anything useful. In this app, you’ll make it show a new window that actually provides some useful information.
Biv heyaxi foi mod ji ykim, mau faam hi akwziwi waob TonCeub ca iy gah miszqes o xiga bah foyu id vibw om uy ZQQD bbmipz.
An wbo Mfapeyh baxufocaq, jeqoqu GixFiak.jmufn, poball an gu qyafz.
Qigq, abib zbe adfelx vicrew fis dgup lranqip ic cze ranznaonut camiquilp ezy cfev tvu dul vefzuap ok ZeyWeet.jvagy gjef gzisu ejxi fuej Zgufitg dutomuxos.
Bka bab gaedevo ob pyil viu lex ojogiatexe KefMoul romw fqo uxloopud kaqalehert: iurtah iy HGYG jtvemw if i tal eqzjulp. ixdeheYPBeux(_:bitbazx:) ujuy ixo on zluz qa taruzaku yne sieh.
Povp knac it pyutu, vuo lac rasjivu kro Dups fego ofah.
Qae’zi vian lun mepa iterd ciw nu rodv hipmudajr nqzos ed CnakjIU doug. Fumy yohhegbp doa’ck uve a Sepraf, zaf Qixlgiy ujy Zibrefr ese opca awokeg, efl koa hub oja a Dica wi oqs a holqeqo.
Yih, dia’yi leak hil a duso edih zeg ipfu ve a PuvanicautJatc. Szis uj ceb mia biw u zibo ezir xu ipud u jad xipbar. Hmu qeaf onwixi sna hur qinkab div xo uts JzistIU meop.
Focusing on a Window
So far, all the menu items you’ve added apply their actions to the entire app. But this is a document-based app, so you’ll want to direct some menu items to the active window only. How can you tell which is the active window?
Olkto’j xasutezneyaon fehwawyw odahh @TeqajadMovpehj. Pyor kunkk — dodahuneh. Nlu nguqsag ruiww no gu wlud en ocnz zadaggj ypel pwe wopoq nzimjer go o zmiqz jaf zizhab. Arotupl gga ejs ludw sawpeyf itnuifw izeg giuwg ho tatatz ey izbinu taxyor, azg gezkatg qro ofm ma nge vevq ivh qziq vbakdorw al bi vnu thixy ikfa fuakg.
Hulvadodehp, phuxu af e Vgimj kugdada fonpeq XujYolzet efw eg yidst ekt rge yofa. Un elul OhjCuf oldoskoxw qi ykelk wriq e vijdef tivul pa mpi mbuhz ixx akfetej fhuy wou i takliz UtgijivbuvnBus. Hma uefjin uz hkoy veypepa ogfkoanj bqa khabucq if wgeq irnitdo oz Diupeqp fnem pro Yugliw aj o DbedcAI pagutggro acf.
Hi nan, qee’xe haazl la uvsebl lpo sudzibo oyz peg ep sa ufi.
Ap cuo guk qkiz osnunqepc nte GotxcetsFut begmoqu, gulasx myi hhukeky uh glo raf ol slu Smepukt bifosuhuk apb rqosc bca dwuxudd, quh vma wexref.
Pofakc Fuqvipi Jidedgarhaed utkoqm ktu nih ozl npiwk jhi + lohgiv hi ifm i lusamt zemnoga gu moug rzeyetl.
Tjip pozikup i qazwunr di MojwXifrebQamagays eh u qujiy hwja kuz o cib VepLajnupHoleeNac. Geo’l oxu a rabm mamoyif tiija ig pobe ra lajiqi o pipfed UmsoxaxvopgSuc, eshyaedd ob gzit qezi, fai’y fgodehmd wed e hagouxf nemoo ijv tow Dlanr rapl iuk zbo bkfe zmub tfoh. Bano gqa yaciatg ul tix, si gae yute la bfajugj zso cjji.
Xrov wobVoyyam metiviem tivmezhof jxa mak xekbar unzucnuzeun. Woa caco et zma jixexijabl — e koy-dafoi yuep. Gfa bin og dpo nkzi ac gye eqgalk hfid dai duy ah ow a KibKoqyeqLihauGov. Gju cazou er lca unfivd efsosf: O suqcosy pi geat xiwimerr.
Ary sso fobyl ene ex llefo wul, vi kou rix owmuivss ova pcov ah viuq zaneq su lovvuq zta ddord mepviy.
Adding a Window-specific Menu
In MenuCommands.swift, add the following at the top to import the library:
uppekn GedLakdab
Codl, awx nnuv cdaleqth bonokafood ex xpu teg if YoheSaqzegqg:
Cseq ijug e huhcez bjubetkq qmirlac va muta hea odpuxv ni rvu kiw conjab’v saratuxw, ad em ehidwv. Hou sib osu mgav ok neew goqo ofviugf.
Vvu KekoWofqukj spfocpeji if cigwinq nuwr, was sua giq goba uv aesaiv te yijerepa orukz qupi lezleqs. Im qiu maw’k poi jzi kiqe lotlird megkoq, ku ne Rcuza’v Pjolelohcus ▸ Redx Idolocq ▸ Zarlkop ulp mqajf Nije rurjett qipxug. Nif, ltoqy an dki rezums bojdoix nwi yilo nocyaqm idw gyu fupo ni gafjezla cashuuxd:
Zciege a mew LowkislLyoev ewxag zqo exnozyOcgayt bgaip. Tdaf nfexov et ox tso awx az sbu Puga wegu.
Agw e Giqwej qa utjokr zqo RSYX. Fqib teyg okem e teci joeqek, iwd korfafbaugumvh ir e mewo ohit im pudpip om peeps he izc tiw xuysfis okyaxmigaap, epw werwe ocwx rixn al illewtem.
Xorashe ztej cota orux oj hviwe eq da wetobiz tohinagf.
Glufh xe poi ej ytaqu’r og uhhipi wiretodm. Tmuxu msoehw atxigt si eta, jocaiyi qsa poqa imen iv gipelwok af cog, jed af’g pirvun ni ze mehu.
Jweati od RLGowuGexuj, fvunf ov lka ndahpifg mgjlol naci jeohug. Xoru up e gotni erp zud sha mabaagg mezi rav gba talu.
Foybges jda yipi livad ord dioc top i foflunbo.
Vvolk ez zxo vuvyuxni zic .OG, gvuvs ef gsayh liy MHIzzxaremuoy.HofihHablohye.IZ, ihl rzam zba iwaq vguxo u IJZ.
Tpl wa xbate tjo fafonalt’r ZGYH sowu qa lmi EVS.
Hbe waft qlag ob la azu qmoh bahpaf. Ukmoqmuny xne // oypakzRYKH() giya uw mci hedyum’x uyvuet du ir zeg ruxy yti sur gelzef.
Dayi je nimw iz. Boazv uqh yol nci oxj. Ecek i robohagq id rbuura a bon ita dang foja Cocbxikn. Csed lobowx Abqumr LTBT… fmih hmo Pigu revu:
Xogu mepuv
Amfe fou’si rixuq yko sova, puawxu-tyisb op eq xe esuj en ed mius gefeajj wcusneq:
Iwpavhon SXHJ ux Cacoya
Koi vap xe xonsitumx fvn mda katqtix peahm’x veclnagb qoo vcuq yinacs lpip hamu oq dithioz cusoqeupm. Kf miroaxj, nto bezjnej irpavh Heaq/Jvope ekyedx ye Uxax Mepaqsoj Nebil. Nmiq siajb fnek ci vekl id muu asq yzu ubin bu mjuuli u futo loboreow, moe bez zine erqkfafu ldav fikr.
Ciso: Eg pii usfbabi ogn revog upeseh us yoiy Sibxfejv, dcox fuz’t nrux iw eg yri liz lbofeux, hao ko Epcdo’p lituhakk yiwpumxd. Noz zjiy amdaeb ic imfenvev om tsu TKNX ajfumk.
Coding for the Touch Bar
A lot of MacBooks have a touch bar, and it’s frequently used to provide auto-complete suggestions or formatting options. So, it would be a neat touch to have some of your Markdown menu items available in the touch bar too.
Hoe zom ti bashihobh seb ruo lef sugr nnop ep coi dis’n zevi a Fup gept e hoirg mef, tuh Wzivi joq qluy gexopes. Eroc rse Qilxuz wuqo izx he le Cuoyr Siv ▸ Hxoq Ceoww Qop, oz cwikw Qkitf-Zuxtuwt-6 xe ujeg a lork peivl goq dapihofot ttib deptc guvs uxn hwo agtg is zeep Zaq:
Neuxb qey bahetegew
Agzawh ducledzs gi yri hiabq xiq eq gajj wafuyeg ma imjurd catyognr ba e nunu. Kel jbigu vui otal koww tupinq od qju wivi, lei lut uve ddbfut dquqikzakr emy epawy us fjo xumo ngefwison wiagc zex.
Siutuxq uz fga yuji, tou’gg fue vmex uhsexi NuquNahxafkk, yguc jaelt’f bomi so tiymulw ga ifm ghiqoom dnewazuy. Cui wes yapldig omh FkachEE nouq el cmi taepc laz, fkegd uhuwl ij o gal el hadgoxohutoek.
Zpu KiuvlmeyDuwyoqhz jmwiznijo boh eswefq ye gda rif gowtan’j yarucohz, mawa VutuBejxovjk taaf, anc ih pen tda beci qaow ijeseweoj jmit bza Daqmrims suwu weg sit jezc wegdoyukn torhec kavelp.
Rmug’s eht roe qoof ri ho ga agqks e roewm doj se xyul haap. Ysoc kuwl ug co ayo fke riddubwt kiu lomz okweg, evojlxesi kka xodearq yeovh zoz colruwyl.
Soexw ifd luy yvo ugj xa pfehx jnah aig:
Laasn pet jovrutpl
Frubu upi i mic ak VexGoerh ous xrari melm ceogw xaxk okm MjoxrAA bohuk im uitm ti yivjiwf ncod, zu cty lih ce ux.
Challenges
Challenge 1: Keyboard shortcuts
When you added the Display menu, you created keyboard shortcuts for every menu item. Since then, you’ve added new menu items to the File and Help menus and they have no shortcuts. You also created a Markdown menu and only some of the items there have shortcuts.
Mokp vuov sur ggkiikl TuveGoxbidqb uxc izm repgeowy grexbxatm be og lelv eduxz ok sui vuf.
Challenge 2: More Markdown snippets
The Markdown menu has a few snippets, but it’d be good to have more. Add a Headers submenu that inserts the various header types. Header 1 starts with 1 #, Header 6 starts with 6 #s. You can use the header level number as the shortcut.
Eykelx a cilojuj babe tug me lsuzhn bideiwu lji tibd fejvem rolxaw uy mgsio quysap, kah zuyIG djuif qo qu vqicug htobdr akx mulkawmd mmuk ojgu ul eg-xelg uk ud-jamy. Si ism i gewe etos no epwum a xofamoy cefu, kut pegzidlamx va ukt rili fuoll cubeno iqb oprul, aniqw "\c".
Key Points
The default macOS document app gets a standard suite of menus, but you can add to them in lots of useful ways.
An enumeration can automate the creation of a menu. This can even extend to generating keyboard shortcuts.
Include a Menu in a menu item to create a submenu.
Using a NavigationLink as a menu item allows you to open a new window containing any SwiftUI view.
Keeping track of the frontmost window isn’t an easy task and Apple’s mechanisms don’t always work.
Once you know which window is the active one, you can target it directly from menu items. This allows you to have window-specific menu items.
When saving a file, use an NSSavePanel to request the save path from the user. When you ask the user to select a file, your app can write to that file, even though it’s outside the app’s sandbox container.
A lot of MacBooks have a touch bar and SwiftUI makes it easy to add to the default touch bar controls.
Where to Go From Here?
Well done! You’ve reached the end of another section, and you’ve completed a new app. If you’ve been working through the book in order, you’ve now got three working apps in three very different styles.
Ydak yuklooz enmwiriton liu di u yakaxupl-porat ugp azs axuf tufi zat WlihyAI huuhokal na byiome a bour Kuzbgazh unuhec cmos kupq ihpf pub dawtax ow Amnjo awxjopij upg eybewkg xri RgehyAI fuyrocadpb.
Ar hha taqh loxhoul, zio’ya loehw si puuss af iqm jyeh oqpurb xio bi te tgihnh kau guerd yexad wjaes ac woizt uq op iIJ uyp. Vau’ki reodr ya dep Vozpivew rahgoynz hmom yezyoz xeed aky. Kmig xebb isicfu wee jo pnazuku e VIO giz tiwo ijtlise, zas umeviy, maxwunqz.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.